Files
RelayBox/RelayBox.cpp

268 lines
6.6 KiB
C++

#include "RelayBox.h"
#include "hardware.h"
#include <avr/wdt.h>
#include <SPI.h>
#include <Ethernet.h>
#include <Metro.h>
#include <Streaming.h>
#include <PubSubClient.h>
#include <PString.h>
#include "config.h"
uint8_t mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x51, 0x07 };
EthernetClient ethClient;
void callback(char* topic, byte* payload, unsigned int length);
// char server[] = "mqttbroker";
char server[] = "192.168.75.1";
PubSubClient client(server, 1883, callback, ethClient);
uint8_t disconnectState = 0;
uint32_t disconnectTime = 0;
Metro minute = Metro(60000);
Metro second = Metro(1000);
uint32_t uptime;
Switch switches[NUM_OF_LINES];
void callback(char* topic, byte* payload, unsigned int length) {
const uint8_t BUFSIZE = 128;
if ((length + 1) >= BUFSIZE) { // 1 for terminating NUL
Serial << "Received message too long, ignore it" << endl;
} else {
char buffer[BUFSIZE];
memcpy(buffer, payload, length);
*(buffer + length) = 0;
Serial << "Received message: " << length << ", " << String(topic) << ", " << String(buffer) << endl;
char *paramPtr = buffer;
char *commandStr = 0;
char *indexStr = 0;
char *stateStr = 0;
if ((paramPtr != 0) && (*paramPtr != 0)){
// command
commandStr = strsep(&paramPtr, " ");
}
if ((paramPtr != 0) && (*paramPtr != 0)){
indexStr = strsep(&paramPtr, " ");
}
if ((paramPtr != 0) && (*paramPtr != 0)){
stateStr = strsep(&paramPtr, " ");
}
if ((commandStr != 0) && (*commandStr != 0) &&
(indexStr != 0) && (*indexStr != 0) &&
(stateStr != 0) && (*stateStr != 0)) {
String command = String(commandStr);
int index = 99;
if (! strcmp(indexStr, "all")) {
index = -1;
} else {
index = atoi(indexStr);
}
String state = String(stateStr);
bool validCommand = command.equals("switch");
bool validIndex = (! ((index < 0) || (index >= NUM_OF_LINES))) || (index == -1);
if (validCommand && validIndex) {
if (state.equalsIgnoreCase("on")) {
if (index == -1) {
for (uint8_t i = 0; i < NUM_OF_LINES; i++) {
switches[i].on();
}
} else {
switches[index].on();
}
} else if (state.equalsIgnoreCase("off")) {
if (index == -1) {
for (uint8_t i = 0; i < NUM_OF_LINES; i++) {
switches[i].off();
}
} else {
switches[index].off();
}
} else if (state.equalsIgnoreCase("toggle")) {
if (index == -1) {
for (uint8_t i = 0; i < NUM_OF_LINES; i++) {
switches[i].toggle();
}
} else {
switches[index].toggle();
}
} else {
Serial << "Invalid state " << state << endl;
}
} else {
if (! validCommand) {
Serial << "Invalid command " << commandStr << endl;
}
if (! validIndex) {
Serial << "Invalid index " << indexStr << endl;
}
}
}
}
}
void setup() {
Serial.begin(9600);
// delay(5000);
Serial << "Starting ... " << endl;
configInit();
Ethernet.begin(mac);
Serial << "Got IP address: " << Ethernet.localIP() << endl;
disconnectState = 3;
disconnectTime = millis();
uptime = 0;
for (uint8_t i = 0; i < NUM_OF_LINES; i++) {
switches[i].begin(FEEDBACK_PIN[i], BUTTON_PIN[i], RELAY_PIN[i], LED_PIN[i], i);
}
wdt_enable(WDTO_8S);
}
void loop() {
wdt_reset();
#ifndef TEST_MODE
for (uint8_t i = 0; i < NUM_OF_LINES; i++) {
switches[i].exec();
}
if (minute.check() == 1) {
byte r = Ethernet.maintain();
Serial << "Ethernet.maintain: " << r << endl;
if ((r == DHCP_CHECK_REBIND_FAIL) || (r == DHCP_CHECK_RENEW_FAIL)) {
}
}
if ((disconnectState == 0) && (! client.loop())) {
disconnectState = 1;
}
switch (disconnectState) {
case 0:
// Serial.println("discState 0");
// everything fine
break;
case 1:
Serial.println("discState 1");
client.disconnect();
disconnectTime = millis();
disconnectState = 2;
break;
case 2:
Serial.println("discState 3");
if (disconnectTime + 2000 < millis()) {
disconnectState = 3;
}
break;
case 3:
Serial.println("discState 3");
if (client.connect("RelayBox")) {
client.subscribe("IoT/Command/RelayBox");
disconnectTime = millis();
disconnectState = 0;
} else {
disconnectState = 1;
}
break;
default:
disconnectState = 0;
break;
}
if (second.check() == 1) {
uptime++;
// Serial.println("tick");
if (disconnectState == 0) {
String msg = String("{ \"metadata\": { \"device\": \"RelayBox\" }, \"data\": { \"uptime\": ") + uptime + String("}}");
client.publish("IoT/Heartbeat/RelayBox", (char*)msg.c_str());
char strbuf[768];
memset(strbuf, sizeof(strbuf), 0);
PString buf = PString(strbuf, sizeof(strbuf));
buf << "{ \"metadata\": { \"device\": \"RelayBox\" }, " <<
"\"data\": {" <<
"\"switchStates\": [";
for (uint8_t i = 0; i < NUM_OF_LINES; i++) {
if (i != 0) {
buf << ", ";
}
buf << "{ \"index\": " << i << ", " <<
"\"state\": " << switches[i].getState() << ", " <<
"\"feedbackState\": " << switches[i].getFeedback() << ", " <<
"\"stateConflict\": " << switches[i].getStateConflict() << " }";
if (switches[i].getStateConflict()) {
Serial << "State conflict on channel " << i << ", should be " << switches[i].getState() <<
", is " << switches[i].getFeedback() << endl;
}
}
buf << "], " <<
"\"uptime\": " << uptime <<
"}" <<
"}" << endl;
//Serial << strbuf << endl;
client.publish("IoT/Status/RelayBox", strbuf);
}
}
#else
for (uint8_t i = 0; i < NUM_OF_LINES; i++) {
digitalWrite(RELAY_PIN[i], false);
digitalWrite(LED_PIN[i], false);
}
delay(500);
for (uint8_t i = 0; i < NUM_OF_LINES; i++) {
digitalWrite(RELAY_PIN[i], true);
delay(100);
}
delay(500);
for (uint8_t i = 0; i < NUM_OF_LINES; i++) {
digitalWrite(RELAY_PIN[i], false);
delay(100);
}
delay(500);
for (uint8_t i = 0; i < NUM_OF_LINES; i++) {
digitalWrite(LED_PIN[i], true);
delay(100);
}
delay(500);
for (uint8_t i = 0; i < NUM_OF_LINES; i++) {
digitalWrite(LED_PIN[i], false);
delay(100);
}
delay(100);
while (true) {
for (uint8_t i = 0; i < NUM_OF_LINES; i++) {
digitalWrite(LED_PIN[i], digitalRead(FEEDBACK_PIN[i]));
digitalWrite(RELAY_PIN[i], digitalRead(BUTTON_PIN[i]));
}
}
#endif
}