Skip to content
Snippets Groups Projects
rest.cpp 5.98 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("/power", powerGroup);

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}";

    // TODO: Add here power sequence status
    // is_ramping_down
    // current step
    // percentage

    message += "\n}";
Cyril Danilevski's avatar
Cyril Danilevski committed

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

void panel() {
    unsigned long elapsed_seconds = (millis() - PINS.last_triggered) / 1000;
Cyril Danilevski's avatar
Cyril Danilevski committed
    String content = buildPanel(PINS.sib, PINS.plc, PINS.ups, elapsed_seconds);
    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,
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;

    for (uint8_t i = 0; i < restServer.args(); i++) {
Cyril Danilevski's avatar
Cyril Danilevski committed
        if (restServer.argName(i) == "output") {
            if (restServer.arg(i) == "on") {
                output = ON;
            } else if (restServer.arg(i) == "off") {
                output = OFF;
            }
        } else if (restServer.argName(i) == "ch") {
            channel = restServer.arg(i).toInt();
        }
Cyril Danilevski's avatar
Cyril Danilevski committed
    }
Cyril Danilevski's avatar
Cyril Danilevski committed
    auto ipAddr = IPAddress(192, 168, 140, 79);
Cyril Danilevski's avatar
Cyril Danilevski committed
    if (output != NONE && channel != 0) {
        setChannelAndWait(&ipAddr, channel, output);
        success = true;  // validates input parameters, not MPOD status, reported separately
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";
        http_msg += mpod.toJSON();
    }

Cyril Danilevski's avatar
Cyril Danilevski committed
    http_msg += "\n}";

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

void powerGroup() {
    String output;
    String group;
    String ret;
    bool success = false;

    for (uint8_t i = 0; i < restServer.args(); i++) {
        if (restServer.argName(i) == "output") {
            if (restServer.arg(i) == "on" || restServer.arg(i) == "off") {
                output = restServer.arg(i);
            }
        } else if (restServer.argName(i) == "group") {
            group = restServer.arg(i);
        }
    }

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

    String http_msg = "{\n";
    http_msg += "\"target\":\"" + pproc.ipAddr.toString() + "\",\n";
    http_msg += "\"arguments\":{";
    http_msg += "\"group\":\"" + group + "\",";
    http_msg += "\"output\":\"" + output + "\"},\n";
    http_msg += "\"success\":" + String(success) + ",\n";
    if (success) {
        http_msg += "\"status\":\n";
        http_msg += pproc.toJSON();
    }
    http_msg += "\n}";
Cyril Danilevski's avatar
Cyril Danilevski committed
    restServer.send(200, "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;
Cyril Danilevski's avatar
Cyril Danilevski committed
    if (!channel) {
        ret = "\"reason\": \"Invalid channel\"";
    } else {
Cyril Danilevski's avatar
Cyril Danilevski committed
        auto ipAddr = IPAddress(192, 168, 140, 79);
        SNMP::Message *snmp_msg = mpod.read(channel);
Cyril Danilevski's avatar
Cyril Danilevski committed
        snmp.send(snmp_msg, ipAddr, SNMP::Port::SNMP);
        delete snmp_msg;
Cyril Danilevski's avatar
Cyril Danilevski committed

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

        ret = mpod.toJSON();
Cyril Danilevski's avatar
Cyril Danilevski committed
    String http_msg = "{\n";
    http_msg += ret;
    http_msg += ",\"success\": ";
    http_msg += channel ? 1 : 0;
Cyril Danilevski's avatar
Cyril Danilevski committed
    http_msg +=
        ",\"channel\": ";  // TODO: test with invalid channel (request w/o "ch" arg). JSON invalid.
    http_msg += channel;
Cyril Danilevski's avatar
Cyril Danilevski committed
    http_msg += "\n}";
Cyril Danilevski's avatar
Cyril Danilevski committed
    restServer.send(200, "text/json", http_msg);