Skip to content
Snippets Groups Projects
rest.cpp 8.36 KiB
Newer Older
Cyril Danilevski's avatar
Cyril Danilevski committed
#include "rest.hpp"
Cyril Danilevski's avatar
Cyril Danilevski committed

#include <ETH.h>

#include "mpod.hpp"
#include "panel.hpp"
#include "pins.hpp"
#include "powerproc.hpp"
#ifndef ICBM_GIT_VERSION
#define ICBM_GIT_VERSION "DEVEL"
#endif

#ifndef ICBM_GIT_TIMESTAMP
#define ICBM_GIT_TIMESTAMP "UNKNOWN"
#endif

Cyril Danilevski's avatar
Cyril Danilevski committed
WebServer restServer(80);

void initializeRoutes() {
    restServer.on("/idn", identify);
    restServer.on("/restart", restart);
Cyril Danilevski's avatar
Cyril Danilevski committed
    restServer.onNotFound(notFound);
    restServer.on("/send", sendSNMP);
    restServer.on("/", panel);
    restServer.on("/poll", pollMPODChannel);
    restServer.on("/mpodstatus", getMpodStatus);

    restServer.on("/power", powerGroup);
    restServer.on("/alloff", powerAllOff);
Cyril Danilevski's avatar
Cyril Danilevski committed
    restServer.begin();
    Serial.println("REST Server Started");
}

void identify() {
    int seconds = millis() / 1000;
    int hours = seconds / 3600;
    int minutes = (seconds / 60) % 60;
    seconds = seconds % 60;

    String message = "{\n";

    message += "\"mac\":\"";
    message += ETH.macAddress();
    message += "\",\n";

    message += "\"version\":\"";
    message += ICBM_GIT_VERSION;
    message += "\",\n";

    message += "\"build date\":\"";
    message += ICBM_GIT_TIMESTAMP;
    message += "\",\n";

    message += "\"uptime\": \"";
    message += hours;
    message += ":";
    message += minutes;
    message += ":";
    message += seconds;
    message += "\",\n";

    message += "\"inputs\":{\n";
    message += "\"sib\":";
    message += PINS.sib;
    message += ",\n";

    message += "\"plc\":";
    message += PINS.plc;
    message += ",\n";

    message += "\"ups\":";
    message += PINS.ups;
    message += ",\n";

    unsigned long elapsed_seconds = (millis() - PINS.last_triggered) / 1000;
    message += "\"sec_since_interrupt\":";
    message += elapsed_seconds;
    message += "\n},";
    message += "\"status\":{\n";
    message += "\"ramping\":";
    message += PINS.ramping;
    message += ",\n";
    message += PINS.stage;
    message += "\n}";
    message += "\n}";
    restServer.send(418, "text/json", message);
void panel() {
    unsigned long elapsed_seconds = (millis() - PINS.last_triggered) / 1000;
    String content =
        buildPanel(PINS.sib, PINS.plc, PINS.ups, elapsed_seconds, PINS.stage, PINS.ramping);
    restServer.send(200, "text/html", content);
}

Cyril Danilevski's avatar
Cyril Danilevski committed
void notFound() {
    String message = "{\n";
    message += "\"uri\":\"";
Cyril Danilevski's avatar
Cyril Danilevski committed
    message += restServer.uri();
    message += "\",\n\"method\":\"";
Cyril Danilevski's avatar
Cyril Danilevski committed
    message += (restServer.method() == HTTP_GET) ? "GET" : "POST";

    message += "\",\n\"arguments\":{";
Cyril Danilevski's avatar
Cyril Danilevski committed
    for (uint8_t i = 0; i < restServer.args(); i++) {
        message += "\n\"" + restServer.argName(i) + "\":\"" + restServer.arg(i) + "\",";
Cyril Danilevski's avatar
Cyril Danilevski committed
    if (restServer.args() != 0) {
        message.remove(message.length() - 1);  // remove trailing comma for valid json
    }
Cyril Danilevski's avatar
Cyril Danilevski committed
    message += "\n}\n}";
    restServer.send(404, "text/json", message);
Cyril Danilevski's avatar
Cyril Danilevski committed
    Serial.println(message);
Cyril Danilevski's avatar
Cyril Danilevski committed
    restServer.send(200);
    ESP.restart();
Cyril Danilevski's avatar
Cyril Danilevski committed
    OFF = 0,
    ON = 1,
    NONE = -1,
    if (PINS.ramping) {
        restServer.send(403, "text/json", "{\"success\": 0, \"reason\": \"ramping ongoing\"}");
        return;
    }
Cyril Danilevski's avatar
Cyril Danilevski committed
    uint8_t output = NONE;
    uint16_t channel = 0;
Cyril Danilevski's avatar
Cyril Danilevski committed
    bool success = false;
    String argName;
    String argVal;
    for (uint8_t i = 0; i < restServer.args(); i++) {
        argName = restServer.argName(i);
        argName.toLowerCase();
        argVal = restServer.arg(i);
        if (argName == "output") {
            argVal.toLowerCase();
            if (argVal == "on") {
Cyril Danilevski's avatar
Cyril Danilevski committed
                output = ON;
            } else if (argVal == "off") {
Cyril Danilevski's avatar
Cyril Danilevski committed
                output = OFF;
            }
        } else if (argName == "ch") {
            channel = argVal.toInt();
Cyril Danilevski's avatar
Cyril Danilevski committed
    }
    auto ipAddr = pproc.ipAddr;
Cyril Danilevski's avatar
Cyril Danilevski committed
    if (output != NONE && channel != 0) {
        setChannelStateAndWait(&ipAddr, channel, output);
        success = mpod.getChannel() ? true : false;
Cyril Danilevski's avatar
Cyril Danilevski committed
    String http_msg = "{\n";
    http_msg += "\"target\":\"" + ipAddr.toString() + "\",\n";
    http_msg += "\"arguments\":{";
    http_msg += "\"channel\":" + String(channel) + ",";
    http_msg += "\"output\":" + String(output) + "},\n";
Cyril Danilevski's avatar
Cyril Danilevski committed
    http_msg += "\"success\":" + String(success);

    if (success) {
        http_msg += ",\n\"status\":";
        http_msg += mpod.toJSON();
    }

Cyril Danilevski's avatar
Cyril Danilevski committed
    http_msg += "\n}";
    restServer.send(success ? 200 : 406, "text/json", http_msg);
void getMpodStatus() {
    if (PINS.ramping) {
        restServer.send(403, "text/json", "{\"success\": 0, \"reason\": \"ramping ongoing\"}");
        return;
    }

    restServer.send(200, "text/json", pproc.toJSON());
}

void powerGroup() {
    if (PINS.ramping) {
        restServer.send(403, "text/json", "{\"success\": 0, \"reason\": \"ramping ongoing\"}");
        return;
    }
    String output;
    String group;
    String ret;
    bool success = false;

    String argName;
    String argVal;
    for (uint8_t i = 0; i < restServer.args(); i++) {
        argName = restServer.argName(i);
        argName.toLowerCase();
        argVal = restServer.arg(i);
        argVal.toLowerCase();

        if (argName == "output") {
            if (argVal == "on" || argVal == "off") {
                output = argVal;
        } else if (argName == "group") {
            argVal.toUpperCase();  // Uppercase to match Karabo definitions
            group = argVal;
        PINS.ramping = true;
        PINS.stage = group;

        if (output == "on") {
            success = pproc.powerOn(group);
        } else if (output == "off") {
            success = pproc.powerOff(group);
        }

        PINS.ramping = false;
        PINS.stage = "";
    }

    String http_msg = "{\n";
    http_msg += "\"arguments\":{";
    http_msg += "\"group\":\"" + group + "\",";
    http_msg += "\"output\":\"" + output + "\"},\n";
    http_msg += "\"success\":" + String(success);
    if (success) {
        http_msg += ",\n\"status\":\n";
        http_msg += pproc.toJSON();
    }
    http_msg += "\n}";

    restServer.send(success ? 200 : 406, "text/json", http_msg);
}

void powerAllOff() {
    if (PINS.ramping) {
        restServer.send(403, "text/json", "{\"success\": 0, \"reason\": \"ramping ongoing\"}");
        return;
    }
    String group;
    String groups;
    bool success = false;

    for (uint8_t i = 0; i < restServer.args(); i++) {
        // Check for token to prevent accidental power down
        if (restServer.argName(i) == "token" && restServer.arg(i) == "CWH") {
            success = true;
        }
    }

    if (success) {
        PINS.ramping = true;
        for (int8_t groupIdx = pproc.stagesCount - 1; groupIdx >= 0; groupIdx--) {
            group = pproc.stages[groupIdx].name;
            groups += group;
            groups += ",";
            PINS.stage = group;
            success = pproc.powerOff(group);
            if (!success) {
                break;
            }
        }
        PINS.ramping = false;
    }

    String http_msg = "{\n";
    http_msg += "\"groups\":\"" + groups + "\",";
    http_msg += "\"success\":" + String(success);
    // if (success) {
    //     http_msg += ",\n\"status\":\n";
    //     http_msg += pproc.toJSON();
    // }
    http_msg += "\n}";
    restServer.send(success ? 200 : 406, "text/json", http_msg);
}

void pollMPODChannel() {
    uint16_t channel = 0;
Cyril Danilevski's avatar
Cyril Danilevski committed
    for (uint8_t i = 0; i < restServer.args(); i++) {
        if (restServer.argName(i) == "ch") {
            channel = restServer.arg(i).toInt();
        }
    }

    String ret = "\"Invalid channel\"";

    if (channel) {
        SNMP::Message *snmp_msg = mpod.read(channel);
        snmp.send(snmp_msg, pproc.ipAddr, SNMP::Port::SNMP);
Cyril Danilevski's avatar
Cyril Danilevski committed
        delete snmp_msg;
Cyril Danilevski's avatar
Cyril Danilevski committed

        delay(MPOD_UPDATE_LATENCY);
        snmp.loop();  // Force loop to update now

        if (mpod.getChannel()) {  // Valid channel requested
            ret = mpod.toJSON();
        }
Cyril Danilevski's avatar
Cyril Danilevski committed
    String http_msg = "{\n";
    http_msg += "\"success\": ";
    http_msg += channel ? 1 : 0;
    http_msg += ",\n";
    http_msg += "\"arguments\": {";
    http_msg += "\"channel\": ";
    http_msg += channel;
    http_msg += "},\n";  // arguments
    http_msg += "\"status\": ";
Cyril Danilevski's avatar
Cyril Danilevski committed
    http_msg += ret;
    http_msg += "}";
    restServer.send(channel ? 200 : 406, "text/json", http_msg);