diff --git a/README.md b/README.md index 3244494a2c3abb5de4cf88314ee76c37c25c5790..1a33f6fe75e2ea77bace3586dff234abd55c4a58 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,9 @@ Available routes are: - `/idn`: provides information about firmware and hardware version, and uptime. It can be queried as a heartbeat, seeing the uptime increasing. +- `/poll?ch=1`: get status of a channel. + + ### Serial Interface The serial interface is available through the micro-usb port. diff --git a/mpod.cpp b/mpod.cpp index 7270e278aa5095ff2147f1019991ad1d8717a2cc..c7d66b66473687c90d7e82f7f3b69f01153aee1e 100644 --- a/mpod.cpp +++ b/mpod.cpp @@ -14,42 +14,37 @@ MPOD::MPOD() { } -// Create an SNMP SETREQUEST message to setup MPOD -SNMP::Message* MPOD::setup() { - // Use read/write community, not read-only - SNMP::Message* message = new SNMP::Message(SNMP::Version::V2C, "guru", SNMP::Type::SetRequest); - // In SETREQUEST, use node type and set the value. - // OUTPUT SWITCH, integer type, 0 is OFF and 1 is ON. - message->add(OID::NAMES[OID::OUTPUTSWITCH], new IntegerBER(0)); - // OUTPUT VOLTAGE is an opaque float embedded in an opaque node - message->add(OID::NAMES[OID::OUTPUTVOLTAGE], new OpaqueBER(new OpaqueFloatBER(10.0))); - // OUTPUT CURRENT is an opaque float embedded in an opaque node - message->add(OID::NAMES[OID::OUTPUTCURRENT], new OpaqueBER(new OpaqueFloatBER(0.001))); - // OUTPUT VOLTAGE RISE RATE is negative. Don't ask me why... - message->add(OID::NAMES[OID::OUTPUTVOLTAGERISERATE], new OpaqueBER(new OpaqueFloatBER(-1.0))); - return message; -} - - // Create an SNMP GETREQUEST message -SNMP::Message* MPOD::read() { +// Create an SNMP GETREQUEST message +SNMP::Message* MPOD::read(uint16_t channel) { SNMP::Message* message = new SNMP::Message(SNMP::Version::V2C, "public", SNMP::Type::GetRequest); // In GETREQUEST, values are always of type NULL. - message->add(OID::NAMES[OID::OUTPUTSTATUS]); - message->add(OID::NAMES[OID::OUTPUTMEASUREMENTSENSEVOLTAGE]); - message->add(OID::NAMES[OID::OUTPUTMEASUREMENTCURRENT]); + String snmp_cmd = OID::NAMES[OID::OUTPUTSTATUS]; + snmp_cmd += channel; + message->add(snmp_cmd.c_str()); + + snmp_cmd = OID::NAMES[OID::OUTPUTMEASUREMENTSENSEVOLTAGE]; + snmp_cmd += channel; + message->add(snmp_cmd.c_str()); + + snmp_cmd = OID::NAMES[OID::OUTPUTMEASUREMENTCURRENT]; + snmp_cmd += channel; + message->add(snmp_cmd.c_str()); + return message; } - // Create an SNMP SETREQUEST message to switch on or off the MPOD -SNMP::Message* MPOD::output(const bool on) { +// Create an SNMP SETREQUEST message to switch on or off the MPOD +SNMP::Message* MPOD::output(const uint16_t channel, const bool on) { SNMP::Message* message = new SNMP::Message(SNMP::Version::V2C, "guru", SNMP::Type::SetRequest); // In SETREQUEST, use node type and set the value. // OUTPUT SWITCH, integer type, 0 is OFF and 1 is ON. - message->add(OID::NAMES[OID::OUTPUTSWITCH], new IntegerBER(on ? 1 : 0)); + String snmp_cmd = OID::NAMES[OID::OUTPUTSWITCH]; + snmp_cmd += channel; + message->add(snmp_cmd.c_str(), new IntegerBER(on ? 1 : 0)); return message; } - // Parse incoming message +// Parse incoming message bool MPOD::message(const SNMP::Message *message) { unsigned int found = 0; unsigned int index = 0; @@ -99,6 +94,12 @@ bool MPOD::message(const SNMP::Message *message) { found++; break; } + + // Get the channel ID from the last value in the varbind name + // No validation is done here as the varbind must be legal to get + // that far. + const char* channel = strrchr(varbind->getName(), '.') + 1; + _channel = atoi(channel); } // Return true if nodes found, that means this is a valid response from MPOD return found; @@ -136,6 +137,10 @@ float MPOD::getVoltageRiseRate() const { return _voltageRiseRate; } +uint16_t MPOD::getChannel() const { + return _channel; +} + // Use appropriate cast to get integer value unsigned int MPOD::getIntegerFromVarBind(const VarBind *varbind) { return static_cast<IntegerBER*>(varbind->getValue())->getValue(); @@ -148,6 +153,7 @@ float MPOD::getFloatFromVarBind(const VarBind *varbind) { String MPOD::toJSON() { String json = "\"status\":{\n"; + json += "\"channel\":" + String(getChannel()) + ","; json += "\"is_on\":" + String(isOn()) + ","; json += "\"is_up\":" + String(isUp()) + ","; json += "\"is_down\":" + String(isDown()) + ","; @@ -170,7 +176,8 @@ MPOD mpod; void onMessage(const SNMP::Message *message, const IPAddress remote, const uint16_t port) { if (mpod.message(message)) { Serial.println(); - Serial.print("MPOD status"); + Serial.print("MPOD status: "); + Serial.print(mpod.getChannel()); Serial.print(mpod.isOn() ? " on" : " off"); if (mpod.isUp()) { Serial.print(" up"); diff --git a/mpod.hpp b/mpod.hpp index 00dc72496b317ddc7097bce73a0d930ca5ea645b..a36d03f06540b360d2736392e202fc9dcda8bef1 100644 --- a/mpod.hpp +++ b/mpod.hpp @@ -27,20 +27,22 @@ class MPOD { }; static inline const char *NAMES[] = { - "1.3.6.1.4.1.19947.1.3.2.1.4.1", - "1.3.6.1.4.1.19947.1.3.2.1.5.1", - "1.3.6.1.4.1.19947.1.3.2.1.7.1", - "1.3.6.1.4.1.19947.1.3.2.1.9.1", - "1.3.6.1.4.1.19947.1.3.2.1.10.1", - "1.3.6.1.4.1.19947.1.3.2.1.12.1", - "1.3.6.1.4.1.19947.1.3.2.1.13.1", + // These are incomplete SNMP commands needing to be + // formatted with the channel id after the final dot + "1.3.6.1.4.1.19947.1.3.2.1.4.", + "1.3.6.1.4.1.19947.1.3.2.1.5.", + "1.3.6.1.4.1.19947.1.3.2.1.7.", + "1.3.6.1.4.1.19947.1.3.2.1.9.", + "1.3.6.1.4.1.19947.1.3.2.1.10.", + "1.3.6.1.4.1.19947.1.3.2.1.12.", + "1.3.6.1.4.1.19947.1.3.2.1.13.", }; // Returns index of OID equals to name // Returns UNKNOWN if none static unsigned int match(const char *name) { for (unsigned int index = 0; index < COUNT; ++index) { - if (strcmp(NAMES[index], name) == 0) { + if (strstr(name, NAMES[index])) { return index; } } @@ -50,9 +52,8 @@ class MPOD { // Create an SNMP SETREQUEST message to setup MPOD MPOD(); - SNMP::Message* setup(); - SNMP::Message* read(); - SNMP::Message* output(const bool); + SNMP::Message* read(const uint16_t); + SNMP::Message* output(const uint16_t, const bool); bool message(const SNMP::Message*); bool isOn() const; bool isUp() const; @@ -62,11 +63,13 @@ class MPOD { float getVoltage() const; float getCurrent() const; float getVoltageRiseRate() const; + uint16_t getChannel() const; String toJSON(); private: unsigned int getIntegerFromVarBind(const VarBind*); float getFloatFromVarBind(const VarBind*); + uint16_t _channel; bool _on; bool _up; bool _down; diff --git a/panel.hpp b/panel.hpp index ae6e2e0b49d8de91b3f2fe1892e57cfa8941f9b8..3696a6d92235f8fc45fec6e6657ffe923ccbb11f 100644 --- a/panel.hpp +++ b/panel.hpp @@ -38,6 +38,7 @@ String buildPanel(bool sib, bool plc, bool ups, unsigned long elapsed_secs) { page += "<h3>Last INT: "; page += elapsed_secs; + page += " secs. ago"; page += "</h3></div></body></html>"; return page; diff --git a/pins.cpp b/pins.cpp index d307577a097c74b331b09af8123fed381de974e7..0a0dc0c2102850053d21eb2d4ce3590d43486ee7 100644 --- a/pins.cpp +++ b/pins.cpp @@ -68,6 +68,6 @@ void toggle_status_led() { if (millis() - toggle_start >= 1000) { toggle_start = millis(); on = !on; - MCP.write1(STATUS_LED_PIN, on); + MCP.write1(STATUS_LED_PIN, on); } } diff --git a/rest.cpp b/rest.cpp index 6ba02388de439d868c61ba21cf073faf711481a9..b3c5247b97d321c10d48d4a0e4f64d95ddcf4dd3 100644 --- a/rest.cpp +++ b/rest.cpp @@ -20,6 +20,7 @@ void initializeRoutes() { restServer.onNotFound(notFound); restServer.on("/send", sendSNMP); restServer.on("/", panel); + restServer.on("/poll", pollMPODChannel); restServer.begin(); Serial.println("REST Server Started"); @@ -128,6 +129,7 @@ enum { void sendSNMP() { uint8_t output = NONE; + uint16_t channel = 0; bool success = false; for (uint8_t i = 0; i < restServer.args(); i++) { @@ -137,32 +139,67 @@ void sendSNMP() { } else if (restServer.arg(i) == "off") { output = OFF; } - } + } else if(restServer.argName(i) == "ch") { + channel = restServer.arg(i).toInt(); + } } auto ipAddr = IPAddress(192,168,140,79); - if (output != NONE) { - SNMP::Message *snmp_msg = mpod.output(output); + if (output != NONE && channel != 0) { + SNMP::Message *snmp_msg = mpod.output(channel, output); snmp.send(snmp_msg, ipAddr, SNMP::Port::SNMP); delete snmp_msg; success = true; } + if (success) { + SNMP::Message *snmp_msg = mpod.read(channel); + snmp.send(snmp_msg, ipAddr, SNMP::Port::SNMP); + delete snmp_msg; + } + String http_msg = "{\n"; - http_msg += "\"target\":\"" + ipAddr.toString() + "\","; - http_msg += "\"arguments\":{\"output\":" + String(output) + "},\n"; + http_msg += "\"target\":\"" + ipAddr.toString() + "\",\n"; + http_msg += "\"arguments\":{"; + http_msg += "\"channel\":" + String(channel) + ","; + http_msg += "\"output\":" + String(output) + "},\n"; http_msg += "\"success\":" + String(success); + + if (success) { + http_msg += ",\n"; + http_msg += mpod.toJSON(); + } + http_msg += "\n}"; restServer.send(200, "text/json", http_msg); } void pollMPODChannel() { - auto ret = mpod.toJSON(); + uint16_t channel = 0; + for(uint8_t i = 0; i < restServer.args(); i++) { + if(restServer.argName(i) == "ch") { + channel = restServer.arg(i).toInt(); + } + } + + String ret; + if(!channel) { + ret = "\"reason\": \"Invalid channel\""; + } else { + auto ipAddr = IPAddress(192,168,140,79); + SNMP::Message *snmp_msg = mpod.read(channel); + snmp.send(snmp_msg, ipAddr, SNMP::Port::SNMP); + delete snmp_msg; + ret = mpod.toJSON(); // TODO: This has stale info at this stage! + } String http_msg = "{\n"; http_msg += ret; - http_msg += ",\"success\": 1"; + http_msg += ",\"success\": "; + http_msg += channel ? 1 : 0; + http_msg += ",\"channel\": "; + http_msg += channel; http_msg += "\n}"; restServer.send(200, "text/json", http_msg); diff --git a/rest.hpp b/rest.hpp index 4cc90398c9fcbf3ff5c773d40a67845426f288ae..c62ab9b2a020b977bdb240cf42bc752f2c25f541 100644 --- a/rest.hpp +++ b/rest.hpp @@ -8,5 +8,6 @@ void initializeRoutes(); void identify(); // /idn void notFound(); // 404 void restart(); // /restart -void sendSNMP(); // /send?output=on -void panel(); //show a status page +void sendSNMP(); // /send?ch=107&output=on +void panel(); // / show a status page +void pollMPODChannel(); // /poll?ch=1