Preliminary support for IO extender based on Arduino Pro Mini through I2C

Added GPIO-9 and GPIO-10 for boards equipped with an ESP12E module (NodeMCU V1.0)
Finished support for PCF8591 4 channel Analog to Digital converter.
Added support for MCP23017 input ports
Unit Name is shown in html title
Show 'well known' devices in the I2C scanner based on their I2C address
Added option to use simple formulas on device values like "%value%/1000"
Fixed char string handling that should be 25 chars max
Added option to turn on/off internal pullup for switch input pins
Added option to set a name for each task (also used for OpenHAB MQTT publishing)
Preliminary support for OpenHAB MQTT protocol
This commit is contained in:
esp8266nu
2015-08-29 15:45:46 +00:00
parent fb0a05a06b
commit ee758a1bb9
7 changed files with 1091 additions and 445 deletions
+222 -133
View File
@@ -61,31 +61,34 @@ boolean Domoticz_getData(int idx, float *data)
//********************************************************************************
// Interface for Sending to Controllers
//********************************************************************************
boolean sendData(byte sensorType, int idx, byte varIndex)
boolean sendData(byte TaskNr, byte sensorType, int idx, byte varIndex)
{
switch (Settings.Protocol)
{
case 1:
case PROTOCOL_DOMOTICZ_HTTP:
Domoticz_sendData(sensorType, idx, varIndex);
break;
case 2:
case PROTOCOL_DOMOTICZ_MQTT:
Domoticz_sendDataMQTT(sensorType, idx, varIndex);
break;
case 3:
case PROTOCOL_NODO_TELNET:
NodoTelnet_sendData(sensorType, idx, varIndex);
case 4:
case PROTOCOL_THINGSPEAK:
ThingsSpeak_sendData(sensorType, idx, varIndex);
break;
case PROTOCOL_OPENHAB_MQTT:
OpenHAB_sendDataMQTT(TaskNr, sensorType, idx, varIndex);
break;
}
if (Settings.MessageDelay != 0)
{
char log[30];
sprintf_P(log, PSTR("HTTP : Delay %u ms"), Settings.MessageDelay);
addLog(LOG_LEVEL_DEBUG_MORE,log);
unsigned long timer = millis() + Settings.MessageDelay;
while (millis() < timer)
backgroundtasks();
}
{
char log[30];
sprintf_P(log, PSTR("HTTP : Delay %u ms"), Settings.MessageDelay);
addLog(LOG_LEVEL_DEBUG_MORE, log);
unsigned long timer = millis() + Settings.MessageDelay;
while (millis() < timer)
backgroundtasks();
}
}
//#endif
@@ -100,7 +103,7 @@ boolean Domoticz_sendData(byte sensorType, int idx, byte varIndex)
sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]);
sprintf_P(log, PSTR("%s%s"), "HTTP : connecting to ", host);
addLog(LOG_LEVEL_DEBUG,log);
addLog(LOG_LEVEL_DEBUG, log);
if (printToWeb)
{
printWebString += log;
@@ -111,7 +114,7 @@ boolean Domoticz_sendData(byte sensorType, int idx, byte varIndex)
if (!client.connect(host, Settings.ControllerPort))
{
connectionFailures++;
addLog(LOG_LEVEL_ERROR,(char*)"HTTP : connection failed");
addLog(LOG_LEVEL_ERROR, (char*)"HTTP : connection failed");
if (printToWeb)
printWebString += F("connection failed<BR>");
return false;
@@ -154,8 +157,8 @@ boolean Domoticz_sendData(byte sensorType, int idx, byte varIndex)
break;
}
url.toCharArray(log, 79);
addLog(LOG_LEVEL_DEBUG_MORE,log);
url.toCharArray(log, 80);
addLog(LOG_LEVEL_DEBUG_MORE, log);
if (printToWeb)
{
printWebString += log;
@@ -174,18 +177,18 @@ boolean Domoticz_sendData(byte sensorType, int idx, byte varIndex)
// Read all the lines of the reply from server and print them to Serial
while (client.available()) {
String line = client.readStringUntil('\n');
line.toCharArray(log,79);
addLog(LOG_LEVEL_DEBUG_MORE,log);
line.toCharArray(log, 80);
addLog(LOG_LEVEL_DEBUG_MORE, log);
if (line.substring(0, 15) == "HTTP/1.1 200 OK")
{
addLog(LOG_LEVEL_DEBUG,(char*)"HTTP : Succes!");
addLog(LOG_LEVEL_DEBUG, (char*)"HTTP : Succes!");
if (printToWeb)
printWebString += F("Success<BR>");
success = true;
}
delay(1);
}
addLog(LOG_LEVEL_DEBUG,(char*)"HTTP : closing connection");
addLog(LOG_LEVEL_DEBUG, (char*)"HTTP : closing connection");
if (printToWeb)
printWebString += F("closing connection<BR>");
@@ -206,7 +209,7 @@ boolean NodoTelnet_sendData(byte sensorType, int var, byte varIndex)
sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]);
sprintf_P(log, PSTR("%s%s"), "TELNT: connecting to ", host);
addLog(LOG_LEVEL_DEBUG,log);
addLog(LOG_LEVEL_DEBUG, log);
if (printToWeb)
{
printWebString += log;
@@ -217,7 +220,7 @@ boolean NodoTelnet_sendData(byte sensorType, int var, byte varIndex)
if (!client.connect(host, Settings.ControllerPort))
{
connectionFailures++;
addLog(LOG_LEVEL_ERROR,(char*)"TELNT: connection failed");
addLog(LOG_LEVEL_ERROR, (char*)"TELNT: connection failed");
if (printToWeb)
printWebString += F("connection failed<BR>");
return false;
@@ -242,30 +245,30 @@ boolean NodoTelnet_sendData(byte sensorType, int var, byte varIndex)
timer = millis() + 1000;
while (client.available() && millis() < timer && !success)
{
String line = client.readStringUntil('\n');
Serial.println(line);
if (line.substring(0, 20) == "Enter your password:")
{
success = true;
Serial.println("Password request ok");
}
delay(1);
{
String line = client.readStringUntil('\n');
Serial.println(line);
if (line.substring(0, 20) == "Enter your password:")
{
success = true;
Serial.println("Password request ok");
}
delay(1);
}
Serial.println("Sending pw");
client.println(Settings.ControllerPassword);
delay(100);
while (client.available())
Serial.write(client.read());
Serial.println("Sending cmd");
client.print(url);
delay(10);
while (client.available())
Serial.write(client.read());
addLog(LOG_LEVEL_DEBUG,(char*)"TELNT: closing connection");
addLog(LOG_LEVEL_DEBUG, (char*)"TELNT: closing connection");
if (printToWeb)
printWebString += F("closing connection<BR>");
@@ -297,7 +300,8 @@ void syslog(char *message)
// handle MQTT messages
void callback(const MQTT::Publish& pub) {
String message = pub.payload_string();
MQTTMessage(&message);
String topic = pub.topic();
MQTTMessage(&topic, &message);
}
@@ -319,7 +323,18 @@ void MQTTConnect()
if (MQTTclient.connect(clientid))
{
Serial.println(F("MQTT : Connected to broker"));
MQTTclient.subscribe("domoticz/out");
switch (Settings.Protocol)
{
case PROTOCOL_DOMOTICZ_MQTT:
MQTTclient.subscribe("domoticz/out");
break;
case PROTOCOL_OPENHAB_MQTT:
String pubname = "/";
pubname += Settings.Name;
pubname += "/#";
MQTTclient.subscribe(pubname);
break;
}
break;
}
else
@@ -333,54 +348,82 @@ void MQTTConnect()
/*********************************************************************************************\
* Parse incoming MQTT message
\*********************************************************************************************/
void MQTTMessage(String *message)
void MQTTMessage(String *topic, String *message)
{
char json[512];
json[0] = 0;
message->toCharArray(json, 511);
// if (Settings.Debug == 3)
// Serial.println(json);
StaticJsonBuffer<512> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(json);
//for (JsonObject::iterator it=root.begin(); it!=root.end(); ++it)
//{
// Serial.println(it->key);
// Serial.println(it->value.asString());
//}
if (root.success())
switch (Settings.Protocol)
{
long idx = root["idx"];
float nvalue = root["nvalue"];
long nvaluealt = root["nvalue"];
const char* name = root["name"];
const char* svalue = root["svalue"];
const char* svalue1 = root["svalue1"];
const char* svalue2 = root["svalue2"];
const char* svalue3 = root["svalue3"];
case PROTOCOL_DOMOTICZ_MQTT:
{
char json[512];
json[0] = 0;
message->toCharArray(json, 512);
if (nvalue == 0)
nvalue = nvaluealt;
StaticJsonBuffer<512> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(json);
Serial.print(F("MQTT : idx="));
Serial.print(idx);
Serial.print(" name=");
Serial.print(name);
Serial.print(" nvalue=");
Serial.print(nvalue);
Serial.print(" svalue=");
Serial.print(svalue);
Serial.print(" svalue1=");
Serial.print(svalue1);
Serial.print(" svalue2=");
Serial.println(svalue2);
Serial.print(" svalue3=");
Serial.println(svalue3);
if (root.success())
{
long idx = root["idx"];
float nvalue = root["nvalue"];
long nvaluealt = root["nvalue"];
const char* name = root["name"];
const char* svalue = root["svalue"];
const char* svalue1 = root["svalue1"];
const char* svalue2 = root["svalue2"];
const char* svalue3 = root["svalue3"];
if (nvalue == 0)
nvalue = nvaluealt;
Serial.print(F("MQTT : idx="));
Serial.print(idx);
Serial.print(" name=");
Serial.print(name);
Serial.print(" nvalue=");
Serial.print(nvalue);
Serial.print(" svalue=");
Serial.print(svalue);
Serial.print(" svalue1=");
Serial.print(svalue1);
Serial.print(" svalue2=");
Serial.println(svalue2);
Serial.print(" svalue3=");
Serial.println(svalue3);
}
else
Serial.println(F("MQTT : json parse error"));
break;
}
case PROTOCOL_OPENHAB_MQTT:
{
Serial.println(*topic);
String sdevice = "";
String spin = "";
String command = topic->substring(1);
int SlashIndex = command.indexOf('/');
if (SlashIndex > 0)
{
command = command.substring(SlashIndex + 1);
SlashIndex = command.indexOf('/');
if (SlashIndex > 0)
{
sdevice = command.substring(0, SlashIndex);
spin = command.substring(SlashIndex + 1);
int pin = spin.toInt();
int value = message->toFloat();
if (sdevice == "gpio")
{
char cmd[80];
sprintf_P(cmd, PSTR("gpio,%u,%u"), pin, value);
Serial.println(cmd);
ExecuteCommand(cmd);
}
}
}
break;
}
}
else
Serial.println(F("MQTT : json parse error"));
}
@@ -403,7 +446,7 @@ boolean Domoticz_sendDataMQTT(byte sensorType, int idx, byte varIndex)
case 1: // single value sensor, used for Dallas, BH1750, etc
root["nvalue"] = 0;
values = UserVar[varIndex - 1];
values.toCharArray(str, 79);
values.toCharArray(str, 80);
root["svalue"] = str;
break;
case 2: // temp + hum + hum_stat, used for DHT11
@@ -412,7 +455,7 @@ boolean Domoticz_sendDataMQTT(byte sensorType, int idx, byte varIndex)
values += ";";
values += UserVar[varIndex];
values += ";0";
values.toCharArray(str, 79);
values.toCharArray(str, 80);
root["svalue"] = str;
break;
case 3: // temp + hum + hum_stat + bar + bar_fore, used for BMP085
@@ -421,7 +464,7 @@ boolean Domoticz_sendDataMQTT(byte sensorType, int idx, byte varIndex)
values += ";0;0;";
values += UserVar[varIndex];
values += ";0";
values.toCharArray(str, 79);
values.toCharArray(str, 80);
root["svalue"] = str;
break;
case 10: // switch
@@ -433,30 +476,76 @@ boolean Domoticz_sendDataMQTT(byte sensorType, int idx, byte varIndex)
break;
}
// JsonArray& data = root.createNestedArray("data");
// data.add(48.756080, 6); // 6 is the number of decimals to print
// data.add(2.302038, 6); // if not specified, 2 digits are printed
// test drive mqtt
//String json = "{\"idx\": 161, \"nvalue\": 1, \"svalue\": \"";
//json += millis()/1000;
//json += "\" }";
//Serial.println(json);
char json[256];
root.printTo(json, sizeof(json));
Serial.print("MQTT : ");
Serial.println(json);
addLog(LOG_LEVEL_DEBUG,json);
addLog(LOG_LEVEL_DEBUG, json);
if (!MQTTclient.publish("domoticz/in", json))
{
Serial.println(F("MQTT publish failed"));
MQTTConnect();
connectionFailures++;
}
else
if (connectionFailures)
connectionFailures--;
else if (connectionFailures)
connectionFailures--;
}
/*********************************************************************************************\
* Send data to Domoticz using MQTT message
\*********************************************************************************************/
boolean OpenHAB_sendDataMQTT(byte TaskNr, byte sensorType, int idx, byte varIndex)
{
// MQTT publish structure:
// /<unit name>/<task name>/<value name>/state
// <unit name> and <task name> are web configurable by the user
// value name is prefixed in the device section for each type of device
char str[80];
String pubname = "";
String value = "";
switch (sensorType)
{
case 1: // single value sensor, used for Dallas, BH1750, etc
pubname = "/";
pubname += Settings.Name;
pubname += "/";
pubname += Settings.TaskDeviceName[TaskNr];
pubname += "/";
pubname += Device[Settings.TaskDeviceNumber[TaskNr]].ValueNames[0];
pubname += "/state";
value = String(UserVar[varIndex - 1]);
Serial.println(pubname);
Serial.println(value);
MQTTclient.publish(pubname, value);
break;
case 2:
case 3:
pubname = "/";
pubname += Settings.Name;
pubname += "/";
pubname += Settings.TaskDeviceName[TaskNr];
pubname += "/";
pubname += Device[Settings.TaskDeviceNumber[TaskNr]].ValueNames[0];
pubname += "/state";
value = String(UserVar[varIndex - 1]);
MQTTclient.publish(pubname, value);
pubname = "/";
pubname += "/";
pubname += Settings.TaskDeviceName[TaskNr];
pubname += "/";
pubname += Device[Settings.TaskDeviceNumber[TaskNr]].ValueNames[1];
pubname += "/state";
value = String(UserVar[varIndex]);
MQTTclient.publish(pubname, value);
break;
case 10: // switch
// if (UserVar[varIndex - 1] == 0)
// else
break;
}
}
struct NodeStruct
@@ -477,7 +566,7 @@ boolean ThingsSpeak_sendData(byte sensorType, int idx, byte varIndex)
sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]);
sprintf_P(log, PSTR("%s%s"), "HTTP : connecting to ", host);
addLog(LOG_LEVEL_DEBUG,log);
addLog(LOG_LEVEL_DEBUG, log);
if (printToWeb)
{
printWebString += log;
@@ -488,7 +577,7 @@ boolean ThingsSpeak_sendData(byte sensorType, int idx, byte varIndex)
if (!client.connect(host, Settings.ControllerPort))
{
connectionFailures++;
addLog(LOG_LEVEL_ERROR,(char*)"HTTP : connection failed");
addLog(LOG_LEVEL_ERROR, (char*)"HTTP : connection failed");
if (printToWeb)
printWebString += F("connection failed<BR>");
return false;
@@ -501,19 +590,19 @@ boolean ThingsSpeak_sendData(byte sensorType, int idx, byte varIndex)
switch (sensorType)
{
case 1: // single value sensor, used for Dallas, BH1750, etc
postDataStr +="&field";
postDataStr += "&field";
postDataStr += idx;
postDataStr += "=";
postDataStr += String(UserVar[varIndex - 1]);
break;
case 2: // dual value
case 3:
postDataStr +="&field";
postDataStr += "&field";
postDataStr += idx;
postDataStr += "=";
postDataStr += String(UserVar[varIndex - 1]);
postDataStr +="&field";
postDataStr += idx+1;
postDataStr += "&field";
postDataStr += idx + 1;
postDataStr += "=";
postDataStr += String(UserVar[varIndex]);
break;
@@ -522,16 +611,16 @@ boolean ThingsSpeak_sendData(byte sensorType, int idx, byte varIndex)
}
postDataStr += "\r\n\r\n";
String postStr = F("POST /update HTTP/1.1\n");
postStr += F("Host: api.thingspeak.com\n");
postStr += F("Connection: close\n");
String postStr = F("POST /update HTTP/1.1\n");
postStr += F("Host: api.thingspeak.com\n");
postStr += F("Connection: close\n");
postStr += F("X-THINGSPEAKAPIKEY: ");
postStr += Settings.ControllerPassword;
postStr += "\n";
postStr += F("Content-Type: application/x-www-form-urlencoded\n");
postStr += F("Content-Length: ");
postStr += postDataStr.length();
postStr += F("\n\n");
postStr += F("Content-Type: application/x-www-form-urlencoded\n");
postStr += F("Content-Length: ");
postStr += postDataStr.length();
postStr += F("\n\n");
postStr += postDataStr;
if (Settings.SerialLogLevel >= LOG_LEVEL_DEBUG_MORE)
@@ -547,28 +636,28 @@ boolean ThingsSpeak_sendData(byte sensorType, int idx, byte varIndex)
// Read all the lines of the reply from server and print them to Serial
while (client.available()) {
if (Settings.SerialLogLevel >= LOG_LEVEL_DEBUG_MORE)
{
sprintf_P(log,PSTR("C1 WS %u FM %u"),WiFi.status(),FreeMem());
Serial.println(log);
}
{
sprintf_P(log, PSTR("C1 WS %u FM %u"), WiFi.status(), FreeMem());
Serial.println(log);
}
String line = client.readStringUntil('\n');
if (Settings.SerialLogLevel >= LOG_LEVEL_DEBUG_MORE)
{
sprintf_P(log,PSTR("C2 WS %u FM %u"),WiFi.status(),FreeMem());
Serial.println(log);
}
line.toCharArray(log,79);
addLog(LOG_LEVEL_DEBUG_MORE,log);
{
sprintf_P(log, PSTR("C2 WS %u FM %u"), WiFi.status(), FreeMem());
Serial.println(log);
}
line.toCharArray(log, 80);
addLog(LOG_LEVEL_DEBUG_MORE, log);
if (line.substring(0, 15) == "HTTP/1.1 200 OK")
{
addLog(LOG_LEVEL_DEBUG,(char*)"HTTP : Succes!");
addLog(LOG_LEVEL_DEBUG, (char*)"HTTP : Succes!");
if (printToWeb)
printWebString += F("Success<BR>");
success = true;
}
delay(1);
}
addLog(LOG_LEVEL_DEBUG,(char*)"HTTP : closing connection");
addLog(LOG_LEVEL_DEBUG, (char*)"HTTP : closing connection");
if (printToWeb)
printWebString += F("closing connection<BR>");
@@ -591,7 +680,7 @@ boolean nodeVariableCopy(byte var, byte unit)
if (Nodes[unit].ip[0] == 0)
{
strcpy(log, "Remote Node unknown");
addLog(LOG_LEVEL_DEBUG,log);
addLog(LOG_LEVEL_DEBUG, log);
if (printToWeb)
{
printWebString += log;
@@ -603,7 +692,7 @@ boolean nodeVariableCopy(byte var, byte unit)
sprintf_P(host, PSTR("%u.%u.%u.%u"), Nodes[unit].ip[0], Nodes[unit].ip[1], Nodes[unit].ip[2], Nodes[unit].ip[3]);
sprintf_P(log, PSTR("%s%s"), "connecting to ", host);
addLog(LOG_LEVEL_DEBUG,log);
addLog(LOG_LEVEL_DEBUG, log);
if (printToWeb)
{
printWebString += log;
@@ -614,7 +703,7 @@ boolean nodeVariableCopy(byte var, byte unit)
if (!client.connect(host, 80))
{
connectionFailures++;
addLog(LOG_LEVEL_ERROR,(char*)"HTTP : connection failed");
addLog(LOG_LEVEL_ERROR, (char*)"HTTP : connection failed");
if (printToWeb)
printWebString += F("connection failed<BR>");
return false;
@@ -628,8 +717,8 @@ boolean nodeVariableCopy(byte var, byte unit)
url += ",";
url += value;
url.toCharArray(log, 79);
addLog(LOG_LEVEL_DEBUG,log);
url.toCharArray(log, 80);
addLog(LOG_LEVEL_DEBUG, log);
if (printToWeb)
{
printWebString += log;
@@ -650,13 +739,13 @@ boolean nodeVariableCopy(byte var, byte unit)
String line = client.readStringUntil('\n');
if (line.substring(0, 15) == "HTTP/1.1 200 OK")
{
addLog(LOG_LEVEL_DEBUG,(char*)"HTTP : Succes!");
addLog(LOG_LEVEL_DEBUG, (char*)"HTTP : Succes!");
if (printToWeb)
printWebString += F("Success<BR>");
success = true;
}
}
addLog(LOG_LEVEL_DEBUG,(char*)"HTTP : closing connection");
addLog(LOG_LEVEL_DEBUG, (char*)"HTTP : closing connection");
if (printToWeb)
printWebString += F("closing connection<BR>");
@@ -684,7 +773,7 @@ void checkUDP()
if (packetBuffer[0] != 255)
{
packetBuffer[len] = 0;
addLog(LOG_LEVEL_DEBUG,packetBuffer);
addLog(LOG_LEVEL_DEBUG, packetBuffer);
#ifdef ESP_CONNEXIO
ExecuteLine(packetBuffer, VALUE_SOURCE_SERIAL);
#endif
@@ -719,8 +808,8 @@ void checkUDP()
char ipaddress[16];
sprintf_P(ipaddress, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]);
char log[80];
sprintf_P(log, PSTR("UDP : %s,%s,%u"), macaddress,ipaddress,unit);
addLog(LOG_LEVEL_DEBUG,log);
sprintf_P(log, PSTR("UDP : %s,%s,%u"), macaddress, ipaddress, unit);
addLog(LOG_LEVEL_DEBUG, log);
}
}
}
@@ -745,7 +834,7 @@ void sendSysInfoUDP(byte repeats)
{
if (Settings.UDPPort == 0)
return;
// 1 byte 'binary token 255'
// 1 byte id
// 6 byte mac
@@ -754,7 +843,7 @@ void sendSysInfoUDP(byte repeats)
// ??? build
// ??
// send my info to the world...
addLog(LOG_LEVEL_DEBUG,(char*)"UDP : Send Sysinfo message");
addLog(LOG_LEVEL_DEBUG, (char*)"UDP : Send Sysinfo message");
for (byte counter = 0; counter < repeats; counter++)
{
uint8_t mac[] = {0, 0, 0, 0, 0, 0};
+171 -31
View File
@@ -1,32 +1,100 @@
void Device_Init()
{
Device[1].Number = DEVICE_DS18B20;
strcpy(Device[1].Name,"Temperature DS18b20");
Device[1].Type = DEVICE_TYPE_SINGLE;
Device[2].Number = DEVICE_DHT11;
strcpy(Device[2].Name,"Temp + Hum DHT 11");
Device[2].Type = DEVICE_TYPE_SINGLE;
Device[3].Number = DEVICE_DHT22;
strcpy(Device[3].Name,"Temp + Hum DHT 22");
Device[3].Type = DEVICE_TYPE_SINGLE;
Device[4].Number = DEVICE_BMP085;
strcpy(Device[4].Name,"Temp + Baro BMP085");
Device[4].Type = DEVICE_TYPE_I2C;
Device[5].Number = DEVICE_BH1750;
strcpy(Device[5].Name,"LUX BH1750");
Device[5].Type = DEVICE_TYPE_I2C;
Device[6].Number = DEVICE_ANALOG;
strcpy(Device[6].Name,"Analog input");
Device[6].Type = DEVICE_TYPE_ANALOG;
Device[7].Number = DEVICE_RFID;
strcpy(Device[7].Name,"RFID Reader");
Device[7].Type = DEVICE_TYPE_DUAL;
Device[8].Number = DEVICE_PULSE;
strcpy(Device[8].Name,"Pulse Counter");
Device[8].Type = DEVICE_TYPE_SINGLE;
Device[9].Number = DEVICE_SWITCH;
strcpy(Device[9].Name,"Switch input");
Device[9].Type = DEVICE_TYPE_SINGLE;
byte x=0;
Device[++x].Number = DEVICE_DS18B20;
strcpy(Device[x].Name,"Temperature DS18b20");
Device[x].Type = DEVICE_TYPE_SINGLE;
Device[x].VType = 1;
Device[x].Ports = 0;
strcpy(Device[x].ValueNames[0],"Temperature");
Device[++x].Number = DEVICE_DHT11;
strcpy(Device[x].Name,"Temp + Hum DHT 11");
Device[x].Type = DEVICE_TYPE_SINGLE;
Device[x].VType = 2;
Device[x].Ports = 0;
strcpy(Device[x].ValueNames[0],"Temperature");
strcpy(Device[x].ValueNames[1],"Humidity");
Device[++x].Number = DEVICE_DHT22;
strcpy(Device[x].Name,"Temp + Hum DHT 22");
Device[x].Type = DEVICE_TYPE_SINGLE;
Device[x].VType = 2;
Device[x].Ports = 0;
strcpy(Device[x].ValueNames[0],"Temperature");
strcpy(Device[x].ValueNames[1],"Humidity");
Device[++x].Number = DEVICE_BMP085;
strcpy(Device[x].Name,"Temp + Baro BMP085");
Device[x].Type = DEVICE_TYPE_I2C;
Device[x].VType = 3;
Device[x].Ports = 0;
strcpy(Device[x].ValueNames[0],"Temperature");
strcpy(Device[x].ValueNames[1],"Pressure");
Device[++x].Number = DEVICE_BH1750;
strcpy(Device[x].Name,"LUX BH1750");
Device[x].Type = DEVICE_TYPE_I2C;
Device[x].VType = 1;
Device[x].Ports = 0;
strcpy(Device[x].ValueNames[0],"LUX");
Device[++x].Number = DEVICE_ANALOG;
strcpy(Device[x].Name,"Analog input");
Device[x].Type = DEVICE_TYPE_ANALOG;
Device[x].VType = 1;
Device[x].Ports = 0;
strcpy(Device[x].ValueNames[0],"Analog");
Device[++x].Number = DEVICE_RFID;
strcpy(Device[x].Name,"RFID Reader");
Device[x].Type = DEVICE_TYPE_DUAL;
Device[x].VType = 1;
Device[x].Ports = 0;
strcpy(Device[x].ValueNames[0],"RFID");
Device[++x].Number = DEVICE_PULSE;
strcpy(Device[x].Name,"Pulse Counter");
Device[x].Type = DEVICE_TYPE_SINGLE;
Device[x].VType = 1;
Device[x].Ports = 0;
strcpy(Device[x].ValueNames[0],"Count");
Device[++x].Number = DEVICE_SWITCH;
strcpy(Device[x].Name,"Switch input");
Device[x].Type = DEVICE_TYPE_SINGLE;
Device[x].VType = 1;
Device[x].Ports = 0;
strcpy(Device[x].ValueNames[0],"Switch");
Device[++x].Number = DEVICE_PCF8591;
strcpy(Device[x].Name,"PCF8591 Analog input");
Device[x].Type = DEVICE_TYPE_I2C;
Device[x].VType = 1;
Device[x].Ports = 4;
strcpy(Device[x].ValueNames[0],"Analog");
Device[++x].Number = DEVICE_MCP23017;
strcpy(Device[x].Name,"MCP23017 input");
Device[x].Type = DEVICE_TYPE_I2C;
Device[x].VType = 1;
Device[x].Ports = 16;
strcpy(Device[x].ValueNames[0],"Switch");
Device[++x].Number = DEVICE_PRO_MINI_ANALOG;
strcpy(Device[x].Name,"ProMini Extender Analog");
Device[x].Type = DEVICE_TYPE_I2C;
Device[x].VType = 1;
Device[x].Ports = 6;
strcpy(Device[x].ValueNames[0],"Analog");
Device[++x].Number = DEVICE_PRO_MINI_DIGITAL;
strcpy(Device[x].Name,"ProMini Extender Digital");
Device[x].Type = DEVICE_TYPE_I2C;
Device[x].VType = 1;
Device[x].Ports = 14;
strcpy(Device[x].ValueNames[0],"Switch");
for (byte x=0; x < TASKS_MAX; x++)
{
@@ -50,9 +118,17 @@ void Device_Init()
pulseinit(Settings.TaskDevicePin1[x], x);
break;
case DEVICE_SWITCH:
Serial.print(F("INIT : InputPullup "));
if (Settings.TaskDevicePin1PullUp[x])
{
Serial.print(F("INIT : InputPullup "));
pinMode(Settings.TaskDevicePin1[x], INPUT_PULLUP);
}
else
{
Serial.print(F("INIT : Input "));
pinMode(Settings.TaskDevicePin1[x], INPUT);
}
Serial.println(Settings.TaskDevicePin1[x]);
pinMode(Settings.TaskDevicePin1[x], INPUT_PULLUP);
break;
}
}
@@ -136,6 +212,33 @@ void pulseinit(byte Par1, byte Index)
}
}
/*********************************************************************************************\
* Extender (Arduino Mini Pro connected through I2C)
* The Mini Pro needs a small sketch to support this
\*********************************************************************************************/
int extender(byte Cmd, byte Port, int Value)
{
uint8_t address = 0x7f;
Wire.beginTransmission(address);
Wire.write(Cmd);
Wire.write(Port);
Wire.write(Value & 0xff);
Wire.write((Value >> 8));
Wire.endTransmission();
if (Cmd == 2 || Cmd == 4)
{
delay(1); // remote unit needs some time to do the adc stuff
Wire.requestFrom(address, (uint8_t)0x1);
if (Wire.available())
{
int portvalue = Wire.read();
//portvalue += Wire.read()*256;
return portvalue;
}
}
return -1;
}
/*********************************************************************************************\
* Analog port
\*********************************************************************************************/
@@ -259,13 +362,49 @@ boolean pcf8591(byte Par1, byte Par2)
Wire.read(); // Read older value first (stored in chip)
UserVar[Par2 - 1] = (float)Wire.read(); // now read actual value and store into Nodo var
Serial.print("PCF : Analog Value : ");
Serial.println(UserVar[Par1 - 1]);
Serial.println(UserVar[Par2 - 1]);
success = true;
}
return success;
}
/*********************************************************************************************\
* MCP23017
* MCP23017 INPUT
\*********************************************************************************************/
boolean mcp23017Read(byte Par1, byte Par2)
{
Serial.println("MCP23017 Read");
boolean success = false;
byte portvalue = 0;
byte unit = (Par1 - 1) / 16;
byte port = Par1 - (unit * 16);
uint8_t address = 0x20 + unit;
byte IOBankConfigReg = 0;
byte IOBankValueReg = 0x12;
if (port > 8)
{
port = port - 8;
IOBankConfigReg++;
IOBankValueReg++;
}
// get the current pin status
Wire.beginTransmission(address);
Wire.write(IOBankValueReg); // IO data register
Wire.endTransmission();
Wire.requestFrom(address, (uint8_t)0x1);
if (Wire.available())
{
portvalue = ((Wire.read() & _BV(port-1)) >> (port-1));
UserVar[Par2 - 1] = (float)portvalue;
Serial.print("MCP : Input Value : ");
Serial.println(UserVar[Par2 - 1]);
success = true;
}
return success;
}
/*********************************************************************************************\
* MCP23017 OUTPUT
\*********************************************************************************************/
boolean mcp23017(byte Par1, byte Par2)
{
@@ -321,6 +460,7 @@ boolean mcp23017(byte Par1, byte Par2)
}
}
/*********************************************************************************************\
* DALLAS
\*********************************************************************************************/
+121 -46
View File
@@ -41,10 +41,12 @@
// RFID Wiegand-26 reader
// MCP23017 I2C IO Expanders
// Analog input (ESP-7/12 only)
// PCF8591 4 port Analog to Digital converter (I2C)
// LCD I2C display 4x20 chars
// Pulse counters
// Simple switch inputs
// Direct GPIO output control to drive relais, mosfets, etc
// Arduino Pro Mini with IO extender sketch, connected through I2C
// ********************************************************************************
// User specific configuration
@@ -65,6 +67,8 @@
// 1 = Domoticz HTTP
// 2 = Domoticz MQTT
// 3 = Nodo Telnet
// 4 = ThingSpeak
// 5 = OpenHAB MQTT
#define UNIT 0
// ********************************************************************************
@@ -77,37 +81,48 @@
// 3 = temp + hum + baro (BMP085)
// 10 = switch
#define ESP_PROJECT_PID 2015050101L
#define ESP_PROJECT_PID 2015050101L
#define ESP_EASY
#define VERSION 4
#define BUILD 15
#define VERSION 5
#define BUILD 16
#define REBOOT_ON_MAX_CONNECTION_FAILURES 30
#define LOG_LEVEL_ERROR 1
#define LOG_LEVEL_INFO 2
#define LOG_LEVEL_DEBUG 3
#define LOG_LEVEL_DEBUG_MORE 4
#define PROTOCOL_DOMOTICZ_HTTP 1
#define PROTOCOL_DOMOTICZ_MQTT 2
#define PROTOCOL_NODO_TELNET 3
#define PROTOCOL_THINGSPEAK 4
#define PROTOCOL_OPENHAB_MQTT 5
#define CMD_REBOOT 89
#define CMD_WIFI_DISCONNECT 135
#define LOG_LEVEL_ERROR 1
#define LOG_LEVEL_INFO 2
#define LOG_LEVEL_DEBUG 3
#define LOG_LEVEL_DEBUG_MORE 4
#define DEVICE_DS18B20 1
#define DEVICE_DHT11 2
#define DEVICE_DHT22 3
#define DEVICE_BMP085 4
#define DEVICE_BH1750 5
#define DEVICE_ANALOG 6
#define DEVICE_RFID 7
#define DEVICE_PULSE 8
#define DEVICE_SWITCH 9
#define CMD_REBOOT 89
#define CMD_WIFI_DISCONNECT 135
#define DEVICES_MAX 10
#define TASKS_MAX 8
#define DEVICE_DS18B20 1
#define DEVICE_DHT11 2
#define DEVICE_DHT22 3
#define DEVICE_BMP085 4
#define DEVICE_BH1750 5
#define DEVICE_ANALOG 6
#define DEVICE_RFID 7
#define DEVICE_PULSE 8
#define DEVICE_SWITCH 9
#define DEVICE_PCF8591 10
#define DEVICE_MCP23017 11
#define DEVICE_PRO_MINI_ANALOG 12
#define DEVICE_PRO_MINI_DIGITAL 13
#define DEVICE_TYPE_SINGLE 1 // connected through 1 datapin
#define DEVICE_TYPE_I2C 2 // connected through I2C
#define DEVICE_TYPE_ANALOG 3 // tout pin
#define DEVICE_TYPE_DUAL 4 // connected through 2 datapins
#define DEVICES_MAX 14
#define TASKS_MAX 8
#define VARS_PER_TASK 2
#define DEVICE_TYPE_SINGLE 1 // connected through 1 datapin
#define DEVICE_TYPE_I2C 2 // connected through I2C
#define DEVICE_TYPE_ANALOG 3 // tout pin
#define DEVICE_TYPE_DUAL 4 // connected through 2 datapins
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
@@ -160,7 +175,7 @@ struct SettingsStruct
int8_t _Pin_wired_out_2;
byte Syslog_IP[4];
unsigned int UDPPort;
unsigned int Switch1;
unsigned int _Switch1;
byte Protocol;
byte IP[4];
byte Gateway[4];
@@ -179,6 +194,10 @@ struct SettingsStruct
unsigned int TaskDeviceID[TASKS_MAX];
int8_t TaskDevicePin1[TASKS_MAX];
int8_t TaskDevicePin2[TASKS_MAX];
char TaskDeviceName[TASKS_MAX][26];
byte TaskDevicePort[TASKS_MAX];
char TaskDeviceFormula[TASKS_MAX][VARS_PER_TASK][26];
boolean TaskDevicePin1PullUp[TASKS_MAX];
} Settings;
struct LogStruct
@@ -193,12 +212,15 @@ struct DeviceStruct
byte Number;
char Name[26];
byte Type;
byte VType;
byte Ports;
char ValueNames[2][26];
} Device[DEVICES_MAX];
boolean printToWeb = false;
String printWebString = "";
float UserVar[2 * TASKS_MAX];
float UserVar[VARS_PER_TASK * TASKS_MAX];
unsigned long pulseCounter[TASKS_MAX];
unsigned long pulseTotalCounter[TASKS_MAX];
byte switchstate[TASKS_MAX];
@@ -269,7 +291,7 @@ void setup()
lcd.print("ESP Easy");
// Setup MQTT Client
if (Settings.Protocol == 2)
if ((Settings.Protocol == 2) || (Settings.Protocol == 5))
MQTTConnect();
sendSysInfoUDP(3);
@@ -369,7 +391,7 @@ void inputCheck()
{
switchstate[x] = state;
UserVar[(x*2+1) - 1] = state;
sendData(10, Settings.TaskDeviceID[x], x*2+1);
sendData(x, 10, Settings.TaskDeviceID[x], x*2+1);
delay(100);
}
}
@@ -386,7 +408,7 @@ void inputCheck()
Serial.print("RFID : Tag : ");
Serial.println(rfid_id);
UserVar[(x*2+1) - 1] = rfid_id;
sendData(1, Settings.TaskDeviceID[x], x*2+1);
sendData(x, 1, Settings.TaskDeviceID[x], x*2+1);
}
}
}
@@ -399,46 +421,99 @@ void SensorSend()
{
if (Settings.TaskDeviceID[x] != 0)
{
byte uvarNr=x * VARS_PER_TASK + 1;
boolean success = false;
switch(Settings.TaskDeviceNumber[x])
{
case DEVICE_DS18B20:
dallas(Settings.TaskDevicePin1[x], x*2+1);
sendData(1, Settings.TaskDeviceID[x], x*2+1);
dallas(Settings.TaskDevicePin1[x], uvarNr);
success = true;
break;
case DEVICE_DHT11:
dht(11, Settings.TaskDevicePin1[x], x*2+1);
if (!isnan(UserVar[(x*2+1) - 1]) && (UserVar[(x*2+2) - 1] > 0))
sendData(2,Settings.TaskDeviceID[x], x*2+1);
dht(11, Settings.TaskDevicePin1[x], uvarNr);
if (!isnan(UserVar[uvarNr - 1]) && (UserVar[(uvarNr+1) - 1] > 0))
success = true;
break;
case DEVICE_DHT22:
dht(22, Settings.TaskDevicePin1[x], x*2+1);
if (!isnan(UserVar[(x*2+1) - 1]) && (UserVar[(x*2+2) - 1] > 0))
sendData(2, Settings.TaskDeviceID[x], x*2+1);
dht(22, Settings.TaskDevicePin1[x], uvarNr);
if (!isnan(UserVar[uvarNr - 1]) && (UserVar[(uvarNr+1) - 1] > 0))
success = true;
break;
case DEVICE_BMP085:
bmp085(x*2+1);
if ((UserVar[(x*2+2) - 1] >= 300) && (UserVar[(x*2+2) - 1] <= 1100))
sendData(3, Settings.TaskDeviceID[x], x*2+1);
bmp085(uvarNr);
if ((UserVar[(uvarNr+1) - 1] >= 300) && (UserVar[(uvarNr+1) - 1] <= 1100))
success = true;
break;
case DEVICE_BH1750:
lux(x*2+1); // read BH1750 LUX sensor and store to var 6
sendData(1, Settings.TaskDeviceID[x], x*2+1);
lux(uvarNr);
success = true;
break;
case DEVICE_ANALOG:
analog(x*2+1); // read ADC and store to var 7
sendData(1, Settings.TaskDeviceID[x], x*2+1);
analog(uvarNr);
success = true;
break;
case DEVICE_PULSE:
UserVar[(x*2+1) - 1] = pulseCounter[x];
sendData(1, Settings.TaskDeviceID[x], x*2+1);
UserVar[uvarNr - 1] = pulseCounter[x];
success = true;
pulseCounter[x] = 0;
break;
case DEVICE_PCF8591:
pcf8591(Settings.TaskDevicePort[x], uvarNr);
success = true;
break;
case DEVICE_MCP23017:
mcp23017Read(Settings.TaskDevicePort[x], uvarNr);
success = true;
break;
case DEVICE_PRO_MINI_ANALOG:
UserVar[uvarNr - 1] = extender(4,Settings.TaskDevicePort[x],0);
success = true;
break;
case DEVICE_PRO_MINI_DIGITAL:
UserVar[uvarNr - 1] = extender(2,Settings.TaskDevicePort[x],0);
success = true;
break;
}
if (success)
{
for (byte varNr=0; varNr < VARS_PER_TASK; varNr++)
{
if (Settings.TaskDeviceFormula[x][varNr][0] !=0)
{
String formula = Settings.TaskDeviceFormula[x][varNr];
float value = UserVar[uvarNr + varNr - 1];
float result = 0;
String svalue = String(value);
formula.replace("%value%",svalue);
Serial.print("CALC : ");
Serial.print(formula);
Serial.print(" = ");
char TmpStr[26];
formula.toCharArray(TmpStr,25);
byte error = Calculate(TmpStr,&result);
if(error == 0)
{
Serial.println(result);
UserVar[uvarNr + varNr - 1] = result;
}
else
{
Serial.print("? error=");
Serial.println(error);
}
}
}
sendData(x, Device[Settings.TaskDeviceNumber[x]].VType, Settings.TaskDeviceID[x], uvarNr);
}
}
}
+262 -1
View File
@@ -47,4 +47,265 @@ void delayedReboot(int rebootDelay)
delay(1000);
}
ESP.reset();
}
}
//################### Calculate #################################
#define CALCULATE_OK 0
#define CALCULATE_ERROR_STACK_OVERFLOW 1
#define CALCULATE_ERROR_BAD_OPERATOR 2
#define CALCULATE_ERROR_PARENTHESES_MISMATCHED 3
#define CALCULATE_ERROR_UNKNOWN_TOKEN 4
#define STACK_SIZE 10 // was 50
#define TOKEN_MAX 20
float globalstack[STACK_SIZE];
float *sp = globalstack-1;
float *sp_max = &globalstack[STACK_SIZE-1];
#define is_operator(c) (c == '+' || c == '-' || c == '*' || c == '/' )
int push(float value)
{
if(sp != sp_max) // Full
{
*(++sp) = value;
return 0;
}
else
return CALCULATE_ERROR_STACK_OVERFLOW;
}
float pop()
{
if(sp != (globalstack-1)) // empty
return *(sp--);
}
float apply_operator(char op, float first, float second)
{
switch(op)
{
case '+':
return first + second;
case '-':
return first - second;
case '*':
return first * second;
case '/':
return first / second;
return 0;
}
}
char *next_token(char *linep)
{
while(isspace(*(linep++)));
while(*linep && !isspace(*(linep++)));
return linep;
}
int RPNCalculate(char* token)
{
if(token[0]==0)
return 0; // geen moeite doen voor een lege string
if(is_operator(token[0]))
{
float second = pop();
float first = pop();
if(push(apply_operator(token[0], first, second)))
return CALCULATE_ERROR_STACK_OVERFLOW;
}
else // Als er nog een is, dan deze ophalen
if(push(atof(token))) // is het een waarde, dan op de stack plaatsen
return CALCULATE_ERROR_STACK_OVERFLOW;
return 0;
}
// operators
// precedence operators associativity
// 3 ! right to left
// 2 * / % left to right
// 1 + - ^ left to right
int op_preced(const char c)
{
switch(c)
{
case '*':
case '/':
return 2;
case '+':
case '-':
return 1;
}
return 0;
}
bool op_left_assoc(const char c)
{
switch(c)
{
case '*':
case '/':
case '+':
case '-':
return true; // left to right
//case '!': return false; // right to left
}
return false;
}
unsigned int op_arg_count(const char c)
{
switch(c)
{
case '*':
case '/':
case '+':
case '-':
return 2;
//case '!': return 1;
}
return 0;
}
int Calculate(const char *input, float* result)
{
const char *strpos = input, *strend = input + strlen(input);
char token[25];
char c, *TokenPos = token;
char stack[32]; // operator stack
unsigned int sl = 0; // stack length
char sc; // used for record stack element
int error=0;
//*sp=0; // bug, it stops calculating after 50 times
sp = globalstack-1;
while(strpos < strend)
{
// read one token from the input stream
c = *strpos;
if(c != ' ')
{
// If the token is a number (identifier), then add it to the token queue.
if((c >= '0' && c <= '9') || c=='.')
{
*TokenPos = c;
++TokenPos;
}
// If the token is an operator, op1, then:
else if(is_operator(c))
{
*(TokenPos)=0;
error=RPNCalculate(token);
TokenPos=token;
if(error)return error;
while(sl > 0)
{
sc = stack[sl - 1];
// While there is an operator token, op2, at the top of the stack
// op1 is left-associative and its precedence is less than or equal to that of op2,
// or op1 has precedence less than that of op2,
// The differing operator priority decides pop / push
// If 2 operators have equal priority then associativity decides.
if(is_operator(sc) && ((op_left_assoc(c) && (op_preced(c) <= op_preced(sc))) || (op_preced(c) < op_preced(sc))))
{
// Pop op2 off the stack, onto the token queue;
*TokenPos = sc;
++TokenPos;
*(TokenPos)=0;
error=RPNCalculate(token);
TokenPos=token;
if(error)return error;
sl--;
}
else
break;
}
// push op1 onto the stack.
stack[sl] = c;
++sl;
}
// If the token is a left parenthesis, then push it onto the stack.
else if(c == '(')
{
stack[sl] = c;
++sl;
}
// If the token is a right parenthesis:
else if(c == ')')
{
bool pe = false;
// Until the token at the top of the stack is a left parenthesis,
// pop operators off the stack onto the token queue
while(sl > 0)
{
*(TokenPos)=0;
error=RPNCalculate(token);
TokenPos=token;
if(error)return error;
sc = stack[sl - 1];
if(sc == '(')
{
pe = true;
break;
}
else
{
*TokenPos = sc;
++TokenPos;
sl--;
}
}
// If the stack runs out without finding a left parenthesis, then there are mismatched parentheses.
if(!pe)
return CALCULATE_ERROR_PARENTHESES_MISMATCHED;
// Pop the left parenthesis from the stack, but not onto the token queue.
sl--;
// If the token at the top of the stack is a function token, pop it onto the token queue.
if(sl > 0)
sc = stack[sl - 1];
}
else
return CALCULATE_ERROR_UNKNOWN_TOKEN;
}
++strpos;
}
// When there are no more tokens to read:
// While there are still operator tokens in the stack:
while(sl > 0)
{
sc = stack[sl - 1];
if(sc == '(' || sc == ')')
return CALCULATE_ERROR_PARENTHESES_MISMATCHED;
*(TokenPos)=0;
error=RPNCalculate(token);
TokenPos=token;
if(error)return error;
*TokenPos = sc;
++TokenPos;
--sl;
}
*(TokenPos)=0;
error=RPNCalculate(token);
TokenPos=token;
if(error)
{
*result=0;
return error;
}
*result=*sp;
return CALCULATE_OK;
}
//################### Einde Calculate #################################
+62 -7
View File
@@ -20,6 +20,21 @@ void ExecuteCommand(char *Line)
// commands to execute io tasks
// ****************************************
if (strcasecmp(Command, "calc") == 0)
{
float result;
if (GetArgv(Line, TmpStr1, 2))
{
String formula = TmpStr1;
float value = 123.45;
String svalue = String(value);
formula.replace("%value%",svalue);
formula.toCharArray(TmpStr1,25);
if(Calculate(TmpStr1,&result)==CALCULATE_OK)
Serial.println(result);
}
}
if (strcasecmp(Command, "GPIO") == 0)
{
if (Par1 >= 0 && Par1 <= 16)
@@ -54,12 +69,38 @@ void ExecuteCommand(char *Line)
}
}
if (strcasecmp(Command, "ExtRead") == 0)
{
uint8_t address = 0x7f;
Wire.requestFrom(address, (uint8_t)Par1);
if (Wire.available())
{
for (byte x=0; x<Par1;x++)
Serial.println(Wire.read());
}
}
if (strcasecmp(Command, "ExtGPIO") == 0)
extender(1,Par1,Par2);
if (strcasecmp(Command, "ExtPWM") == 0)
extender(3,Par1,Par2);
if (strcasecmp(Command, "ExtGPIORead") == 0)
{
byte value=extender(2,Par1,0);
Serial.println(value);
}
if (strcasecmp(Command, "ExtADCRead") == 0)
{
int value=extender(4,Par1,0);
Serial.println(value);
}
if (strcasecmp(Command, "DomoticzSend") == 0)
{
if (GetArgv(Line, TmpStr1, 4))
{
UserVar[10 - 1] = atof(TmpStr1);
sendData(Par1, Par2, 10);
sendData(0, Par1, Par2, 10);
}
}
@@ -151,18 +192,25 @@ void ExecuteCommand(char *Line)
Serial.println("?");
}
if (strcasecmp(Command, "IP") == 0)
{
if (GetArgv(Line, TmpStr1, 2))
Settings.IP_Octet = str2int(TmpStr1);
}
if (strcasecmp(Command, "ControllerPort") == 0)
{
if (GetArgv(Line, TmpStr1, 2))
Settings.ControllerPort = str2int(TmpStr1);
}
if (strcasecmp(Command, "IP") == 0)
{
if (GetArgv(Line, TmpStr1, 2))
if (!str2ip(TmpStr1, Settings.IP))
Serial.println("?");
}
if (strcasecmp(Command, "IPoctet") == 0)
{
if (GetArgv(Line, TmpStr1, 2))
Settings.IP_Octet = str2int(TmpStr1);
}
if (strcasecmp(Command, "WifiSSID") == 0)
{
GetArgv(Line, TmpStr1, 2);
@@ -232,6 +280,8 @@ void ExecuteCommand(char *Line)
Serial.print(" Fixed IP octet : "); Serial.println(Settings.IP_Octet);
Serial.print(" WifiKey (APmode) : "); Serial.println(Settings.WifiAPKey);
Serial.print(" settings size : "); Serial.println(sizeof(struct SettingsStruct));
}
if (strcasecmp(Command, "Freemem") == 0)
@@ -432,6 +482,11 @@ void ResetFactory(void)
Settings.TaskDeviceID[x]=0;
Settings.TaskDevicePin1[x]=-1;
Settings.TaskDevicePin2[x]=-1;
Settings.TaskDevicePin1PullUp[x]=true;
Settings.TaskDeviceName[x][0]=0;
Settings.TaskDevicePort[x]=0;
for (byte varNr=0; varNr < VARS_PER_TASK; varNr++)
(Settings.TaskDeviceFormula[x][varNr][0] ==0);
}
Save_Settings();
WifiDisconnect();
+154 -141
View File
@@ -24,6 +24,9 @@ void WebServerInit()
void addMenu(String& str)
{
// Inline style definitions
str += F("<head><title>");
str += Settings.Name;
str += F("</title></head>");
str += F("<style>");
str += F("* {font-family:sans-serif; font-size:12pt;}");
str += F("h1 {font-size:16pt; border:1px solid #333; color:#ffffff; background:#27f;}");
@@ -70,7 +73,7 @@ void handle_root() {
Serial.println(webrequest);
char command[80];
command[0] = 0;
webrequest.toCharArray(command, 79);
webrequest.toCharArray(command, 80);
if ((strcasecmp(command, "wifidisconnect") != 0) && (strcasecmp(command, "reboot") != 0))
{
@@ -218,35 +221,35 @@ void handle_config() {
if (ssid[0] != 0)
{
name.replace("+", " ");
name.toCharArray(tmpstring, 25);
name.toCharArray(tmpstring, 26);
strcpy(Settings.Name, tmpstring);
password.toCharArray(tmpstring, 25);
password.toCharArray(tmpstring, 26);
strcpy(Settings.Password, tmpstring);
ssid.toCharArray(tmpstring, 25);
ssid.toCharArray(tmpstring, 26);
strcpy(Settings.WifiSSID, tmpstring);
key.toCharArray(tmpstring, 25);
key.toCharArray(tmpstring, 26);
strcpy(Settings.WifiKey, tmpstring);
controllerip.toCharArray(tmpstring, 25);
controllerip.toCharArray(tmpstring, 26);
str2ip(tmpstring, Settings.Controller_IP);
Settings.ControllerPort = controllerport.toInt();
controlleruser.toCharArray(tmpstring, 25);
controlleruser.toCharArray(tmpstring, 26);
strcpy(Settings.ControllerUser, tmpstring);
controllerpassword.toCharArray(tmpstring, 25);
controllerpassword.toCharArray(tmpstring, 26);
strcpy(Settings.ControllerPassword, tmpstring);
Settings.Protocol = protocol.toInt();
Settings.Delay = sensordelay.toInt();
Settings.MessageDelay = messagedelay.toInt();
Settings.IP_Octet = ip.toInt();
espip.toCharArray(tmpstring, 25);
espip.toCharArray(tmpstring, 26);
str2ip(tmpstring, Settings.IP);
espgateway.toCharArray(tmpstring, 25);
espgateway.toCharArray(tmpstring, 26);
str2ip(tmpstring, Settings.Gateway);
espsubnet.toCharArray(tmpstring, 25);
espsubnet.toCharArray(tmpstring, 26);
str2ip(tmpstring, Settings.Subnet);
Settings.Unit = unit.toInt();
apkey.toCharArray(tmpstring, 25);
apkey.toCharArray(tmpstring, 26);
strcpy(Settings.WifiAPKey, tmpstring);
syslogip.toCharArray(tmpstring, 25);
syslogip.toCharArray(tmpstring, 26);
str2ip(tmpstring, Settings.Syslog_IP);
Settings.UDPPort = udpport.toInt();
Settings.SyslogLevel = sysloglevel.toInt();
@@ -280,14 +283,15 @@ void handle_config() {
reply += F("'><TR><TD>Protocol:");
byte choice = Settings.Protocol;
String options[5];
String options[6];
options[0] = F("");
options[1] = F("Domoticz HTTP");
options[2] = F("Domoticz MQTT");
options[3] = F("Nodo Telnet");
options[4] = F("ThingsSpeak HTTP");
options[5] = F("OpenHAB MQTT");
reply += F("<TD><select name='protocol'>");
for (byte x = 0; x < 5; x++)
for (byte x = 0; x < 6; x++)
{
reply += F("<option value='");
reply += x;
@@ -372,6 +376,8 @@ void handle_config() {
void handle_devices() {
if (!isLoggedIn()) return;
char tmpstring[26];
if (Settings.SerialLogLevel >= LOG_LEVEL_DEBUG)
Serial.println(F("HTTP : Webtasks"));
@@ -380,12 +386,29 @@ void handle_devices() {
String taskdeviceid = WebServer.arg("taskdeviceid");
String taskdevicepin1 = WebServer.arg("taskdevicepin1");
String taskdevicepin2 = WebServer.arg("taskdevicepin2");
String taskdevicepin1pullup = WebServer.arg("taskdevicepin1pullup");
String taskdevicename = WebServer.arg("taskdevicename");
String taskdeviceport = WebServer.arg("taskdeviceport");
String taskdeviceformula[VARS_PER_TASK];
for (byte varNr=0; varNr < VARS_PER_TASK; varNr++)
{
String arg = "taskdeviceformula";
arg += varNr + 1;
char argc[20];
arg.toCharArray(argc,20);
taskdeviceformula[varNr] = WebServer.arg(argc);
}
String edit = WebServer.arg("edit");
byte index = taskindex.toInt();
if (edit.toInt() != 0)
{
Settings.TaskDeviceNumber[index-1] = taskdevicenumber.toInt();
taskdevicename.replace("+", " ");
taskdevicename.toCharArray(tmpstring, 26);
strcpy(Settings.TaskDeviceName[index-1], tmpstring);
Settings.TaskDevicePort[index-1] = taskdeviceport.toInt();
Settings.TaskDeviceID[index-1] = taskdeviceid.toInt();
Settings.TaskDevicePin1[index-1] = taskdevicepin1.toInt();
Settings.TaskDevicePin2[index-1] = taskdevicepin2.toInt();
@@ -394,6 +417,19 @@ void handle_devices() {
if (Device[Settings.TaskDeviceNumber[index-1]].Type != DEVICE_TYPE_DUAL)
Settings.TaskDevicePin2[index-1] = -1;
if (Device[Settings.TaskDeviceNumber[index-1]].Number == DEVICE_SWITCH)
Settings.TaskDevicePin1PullUp[index-1] = (taskdevicepin1pullup == "on");
for (byte varNr=0; varNr < VARS_PER_TASK; varNr++)
{
taskdeviceformula[varNr].replace("%25", "%");
taskdeviceformula[varNr].replace("%28", "(");
taskdeviceformula[varNr].replace("%29", ")");
taskdeviceformula[varNr].replace("%2B", "+");
taskdeviceformula[varNr].replace("%2F", "/");
taskdeviceformula[varNr].toCharArray(tmpstring, 26);
strcpy(Settings.TaskDeviceFormula[index-1][varNr], tmpstring);
}
#ifdef ESP_CONNEXIO
createEventlist();
#endif
@@ -403,8 +439,15 @@ void handle_devices() {
String reply = "";
addMenu(reply);
// show all tasks as table
reply += F("<table border='1' bgcolor='#ddeeff'><tr bgcolor='#55bbff'><td><TD>Task<TD>Device<td>Name<TD>Port<TD>IDX/Variable<TD>1st GPIO<TD>2nd GPIO");
for (byte varNr=0; varNr < VARS_PER_TASK; varNr++)
{
reply += F("<TD>Value ");
reply += varNr + 1;
}
reply += F("<table border='1' bgcolor='#ddeeff'><tr bgcolor='#55bbff'><td><TD>Task<TD>Device<td>IDX/Variable<TD>1st GPIO<TD>2nd GPIO<TD>Value 1<TD>Value2");
for (byte x=0; x < TASKS_MAX; x++)
{
reply += F("<TR><TD>");
@@ -416,6 +459,11 @@ void handle_devices() {
reply += F("<TD>");
reply += Device[Settings.TaskDeviceNumber[x]].Name;
reply += F("<TD>");
reply += Settings.TaskDeviceName[x];
reply += F("<TD>");
if (Device[Settings.TaskDeviceNumber[x]].Ports != 0)
reply += Settings.TaskDevicePort[x];
reply += F("<TD>");
reply += Settings.TaskDeviceID[x];
reply += F("<TD>");
@@ -455,14 +503,16 @@ void handle_devices() {
}
else
{
reply += F("<TD>");
reply += UserVar[2*x];
reply += F("<TD>");
reply += UserVar[2*x+1];
for (byte varNr=0; varNr < VARS_PER_TASK; varNr++)
{
reply += F("<TD>");
reply += UserVar[x * VARS_PER_TASK + varNr];
}
}
}
reply += F("</table>");
// Show edit form is a specific entry is chosen with the edit button
if (index != 0)
{
reply += F("<BR><BR><form method='post'><table bgcolor='#ddeeff'><tr bgcolor='#55bbff'><td>Task Settings<td>Value");
@@ -483,7 +533,15 @@ void handle_devices() {
}
reply += F("</select>");
reply += F("<TR><TD>IDX / Var:<TD><input type='text' name='taskdeviceid' value='");
reply += F("<TR><TD>Name:<TD><input type='text' maxlength='25' name='taskdevicename' value='");
reply += Settings.TaskDeviceName[index-1];
if (Device[Settings.TaskDeviceNumber[index-1]].Ports != 0)
{
reply += F("'><TR><TD>Port:<TD><input type='text' name='taskdeviceport' value='");
reply += Settings.TaskDevicePort[index-1];
}
reply += F("'><TR><TD>IDX / Var:<TD><input type='text' name='taskdeviceid' value='");
reply += Settings.TaskDeviceID[index-1];
reply += F("'>");
@@ -497,6 +555,27 @@ void handle_devices() {
reply += F("<TR><TD>2nd GPIO:<TD>");
addPinSelect(false, reply,"taskdevicepin2",Settings.TaskDevicePin2[index-1]);
}
if (Device[Settings.TaskDeviceNumber[index-1]].Number == DEVICE_SWITCH)
{
reply += F("<TR><TD>Pull UP:<TD>");
if (Settings.TaskDevicePin1PullUp[index-1])
reply += F("<input type=checkbox name=taskdevicepin1pullup checked>");
else
reply += F("<input type=checkbox name=taskdevicepin1pullup>");
}
for (byte varNr=0; varNr < VARS_PER_TASK; varNr++)
{
reply += F("<TR><TD>Formula Value ");
reply += varNr + 1;
reply += F(":<TD><input type='text' maxlength='25' name='taskdeviceformula");
reply += varNr + 1;
reply += F("' value='");
reply += Settings.TaskDeviceFormula[index-1][varNr];
reply += F("'>");
}
reply += F("<TR><TD><TD><a class=\"button-link\" href=\"devices\">Cancel</a>");
reply += F("<input class=\"button-link\" type='submit' value='Submit'><TR><TD>");
reply += F("<input type='hidden' name='edit' value='1'>");
@@ -507,94 +586,6 @@ void handle_devices() {
WebServer.send(200, "text/html", reply);
}
#ifdef ESP_CONNEXIO
void createEventlist()
{
struct NodoEventStruct TempEvent;
ClearEvent(&TempEvent);
byte x = 1;
while (Eventlist_Write(x++, &TempEvent, &TempEvent)) delay(1);
char cmd[80];
sprintf_P(cmd, PSTR("eventlistwrite; boot %u; TimerSet 1,%u"), Settings.Unit, Settings.Delay);
ExecuteLine(cmd, VALUE_SOURCE_SERIAL);
sprintf_P(cmd, PSTR("eventlistwrite; Timer 1; TimerSet 1,%u"), Settings.Delay);
ExecuteLine(cmd, VALUE_SOURCE_SERIAL);
for (byte x=0; x < TASKS_MAX; x++)
{
if (Settings.TaskDeviceID[x] != 0)
{
switch(Settings.TaskDeviceNumber[x])
{
case DEVICE_DS18B20:
sprintf_P(cmd, PSTR("DallasRead %u,%u"), Settings.TaskDevicePin1[x], x*2+1);
eventAddTimer(cmd);
eventAddVarSend(x*2+1, 1, Settings.TaskDeviceID[x]);
break;
case DEVICE_DHT11:
sprintf_P(cmd, PSTR("DHTRead %u,%u,11"), Settings.TaskDevicePin1[x], x*2+1);
eventAddTimer(cmd);
eventAddVarSend(x*2+1, 2, Settings.TaskDeviceID[x]);
break;
case DEVICE_DHT22:
sprintf_P(cmd, PSTR("DHTRead %u,%u,22"), Settings.TaskDevicePin1[x], x*2+1);
eventAddTimer(cmd);
eventAddVarSend(x*2+1, 2, Settings.TaskDeviceID[x]);
break;
case DEVICE_BMP085:
sprintf_P(cmd, PSTR("BMP085Read %u"), x*2+1);
eventAddTimer(cmd);
eventAddVarSend(x*2+1, 3, Settings.TaskDeviceID[x]);
break;
case DEVICE_BH1750:
sprintf_P(cmd, PSTR("LuxRead %u"), x*2+1);
eventAddTimer(cmd);
eventAddVarSend(x*2+1, 1, Settings.TaskDeviceID[x]);
break;
case DEVICE_ANALOG:
sprintf_P(cmd, PSTR("VariableWiredAnalog %u"), x*2+1);
eventAddTimer(cmd);
eventAddVarSend(x*2+1, 1, Settings.TaskDeviceID[x]);
break;
}
if (Settings.MessageDelay != 0)
eventAddDelay();
}
}
}
void eventAddVarSend(byte var, byte sensortype, int idx)
{
char cmd[80];
char strProtocol[5];
if (Settings.Protocol == 1)
strcpy(strProtocol, "HTTP");
if (Settings.Protocol == 2)
strcpy(strProtocol, "MQTT");
if (Settings.Protocol == 3)
strcpy(strProtocol, "TELNET");
if (Settings.Protocol == 4)
strcpy(strProtocol, "TSPK");
sprintf_P(cmd, PSTR("eventlistwrite; Timer 1; VariableSend %u,%s,%u,%u"), var, strProtocol, sensortype, idx);
ExecuteLine(cmd, VALUE_SOURCE_SERIAL);
}
void eventAddTimer(char* event)
{
char cmd[80];
sprintf_P(cmd, PSTR("eventlistwrite; Timer 1; %s"), event);
ExecuteLine(cmd, VALUE_SOURCE_SERIAL);
}
void eventAddDelay()
{
char cmd[80];
sprintf_P(cmd, PSTR("eventlistwrite; Timer 1; Delay %u"), Settings.MessageDelay);
ExecuteLine(cmd, VALUE_SOURCE_SERIAL);
}
#endif
//********************************************************************************
// Web Interface hardware page
@@ -633,32 +624,36 @@ void handle_hardware() {
void addPinSelect(boolean forI2C, String& str, String name, int choice)
{
String options[10];
String options[12];
options[0] = F(" ");
options[1] = F("GPIO-0");
options[2] = F("GPIO-2");
options[3] = F("GPIO-4");
options[4] = F("GPIO-5");
options[5] = F("GPIO-12");
options[6] = F("GPIO-13");
options[7] = F("GPIO-14");
options[8] = F("GPIO-15");
options[9] = F("GPIO-16");
int optionValues[10];
options[5] = F("GPIO-9");
options[6] = F("GPIO-10");
options[7] = F("GPIO-12");
options[8] = F("GPIO-13");
options[9] = F("GPIO-14");
options[10] = F("GPIO-15");
options[11] = F("GPIO-16");
int optionValues[12];
optionValues[0] = -1;
optionValues[1] = 0;
optionValues[2] = 2;
optionValues[3] = 4;
optionValues[4] = 5;
optionValues[5] = 12;
optionValues[6] = 13;
optionValues[7] = 14;
optionValues[8] = 15;
optionValues[9] = 16;
optionValues[5] = 9;
optionValues[6] = 10;
optionValues[7] = 12;
optionValues[8] = 13;
optionValues[9] = 14;
optionValues[10] = 15;
optionValues[11] = 16;
str += F("<select name='");
str += name;
str += "'>";
for (byte x = 0; x < 10; x++)
for (byte x = 0; x < 12; x++)
{
str += F("<option value='");
str += optionValues[x];
@@ -707,10 +702,10 @@ void handle_json() {
Serial.println(svalue);
char c_idx[10];
c_idx[0] = 0;
idx.toCharArray(c_idx, 9);
idx.toCharArray(c_idx, 10);
char c_svalue[40];
c_svalue[0] = 0;
svalue.toCharArray(c_svalue, 39);
svalue.toCharArray(c_svalue, 40);
struct TransmissionStruct event;
event.Type = 1;
@@ -768,7 +763,7 @@ void handle_eventlist() {
struct NodoEventStruct TempEvent;
ClearEvent(&TempEvent);
byte x = 1;
while (Eventlist_Write(x++, &TempEvent, &TempEvent)) delay(1);
while (Eventlist_Write(x++, 0, &TempEvent, &TempEvent)) delay(1);
String eventlist = WebServer.arg("eventlist");
eventlist.replace("%0D%0A", "\n");
@@ -782,13 +777,9 @@ void handle_eventlist() {
line.replace("%3B", ";");
line.replace("%2C", ",");
line.replace("+", " ");
//int SemiColonIndex = line.indexOf(';');
//line = line.substring(SemiColonIndex+1);
String strCommand = F("eventlistwrite;");
String strCommand = F("eventlistwrite 0,");
strCommand += line;
if (Settings.SerialLogLevel >= LOG_LEVEL_DEBUG)
Serial.println(strCommand);
strCommand.toCharArray(TempString, 79);
strCommand.toCharArray(TempString, 80);
messagecode = ExecuteLine(TempString, VALUE_SOURCE_SERIAL);
if (messagecode > 0)
{
@@ -879,7 +870,7 @@ void handle_tools() {
Serial.println(webrequest);
char command[80];
command[0] = 0;
webrequest.toCharArray(command, 79);
webrequest.toCharArray(command, 80);
String reply = "";
addMenu(reply);
@@ -926,31 +917,53 @@ void handle_i2cscanner() {
String reply = "";
addMenu(reply);
reply += F("<table bgcolor='#ddeeff'><tr bgcolor='#55bbff'><td>I2C Addresses in use<TR><TD>");
reply += F("<table bgcolor='#ddeeff'><tr bgcolor='#55bbff'><td>I2C Addresses in use<TD>Known devices");
byte error, address;
int nDevices;
nDevices = 0;
for(address = 1; address < 127; address++ )
for(address = 1; address <= 127; address++ )
{
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0)
{
reply += "0x";
reply += "<TR><TD>0x";
reply += String(address,HEX);
reply += "<BR>";
reply += "<TD>";
switch(address)
{
case 0x20:
case 0x27:
reply += F("PCF8574, MCP23017, LCD Modules");
break;
case 0x23:
reply += F("BH1750 Lux Sensor");
break;
case 0x48:
reply += F("PCF8591 ADC");
break;
case 0x68:
reply += F("DS1307 RTC");
break;
case 0x77:
reply += F("BMP085");
break;
case 0x7f:
reply += F("Arduino Pro Mini IO Extender");
break;
}
nDevices++;
}
else if (error==4)
{
reply += F("Unknow error at address 0x");
reply += F("<TR><TD>Unknow error at address 0x");
reply += String(address,HEX);
}
}
if (nDevices == 0)
reply += F("No I2C devices found");
reply += F("<TR>No I2C devices found");
reply += F("</table>");
addFooter(reply);
@@ -959,7 +972,7 @@ void handle_i2cscanner() {
}
//********************************************************************************
// Web Interface I2C scanner
// Web Interface Wifi scanner
//********************************************************************************
void handle_wifiscanner() {
if (!isLoggedIn()) return;
@@ -1006,7 +1019,7 @@ void handle_login() {
Serial.println(webrequest);
char command[80];
command[0] = 0;
webrequest.toCharArray(command, 79);
webrequest.toCharArray(command, 80);
String reply = "";
reply += F("<form method='post'>");
@@ -1049,7 +1062,7 @@ void handle_control() {
Serial.println(webrequest);
char command[80];
command[0] = 0;
webrequest.toCharArray(command, 79);
webrequest.toCharArray(command, 80);
boolean validCmd = false;
char Cmd[40];
+99 -86
View File
@@ -1,17 +1,92 @@
// R001 01-05-2015
// First 'stable' edition (meaning that it does not crash during boot of within one minute...)
// R016 29-08-2015
// Preliminary support for IO extender based on Arduino Pro Mini through I2C
// Added GPIO-9 and GPIO-10 for boards equipped with an ESP12E module (NodeMCU V1.0)
// Finished support for PCF8591 4 channel Analog to Digital converter.
// Added support for MCP23017 input ports
// Unit Name is shown in html title
// Show 'well known' devices in the I2C scanner based on their I2C address
// Added option to use simple formulas on device values like "%value%/1000"
// Fixed char string handling that should be 25 chars max
// Added option to turn on/off internal pullup for switch input pins
// Added option to set a name for each task (also used for OpenHAB MQTT publishing)
// Preliminary support for OpenHAB MQTT protocol
// R002 02-05-2015
// Added configuration webinterface
// Start AP mode is ssid is not configured
// R015 22-08-2015
// Fixed a bug in DHT22 device
// Fixed a bug in setting for default delay
// Changed debug info
// Changed device tab, added more pin info and cancel button
// Fixed syslog loop bug
// R003 06-05-2015
// Start AP mode if no connection, leave AP mode 30 seconds after succesfull connection
// Added option to set a fixed last octet of the ESP IP address (remaining config is still done with DHCP)
// This is the easiest way. You can still change subnet,gw,dns with DHCP but have a fixed IP
// This is convenient to control ESP with Domoticz http requests (relais, io expander, etc)
// Support for Domoticz multiple value sensor types (temp/hum/baro)
// Added support for pulsecounter
// R014 20-08-2015
// Redesigned device configuration mechanisme
// Changed password timeout to 5 minutes
// Added direct GPIO output control without password request
// R013 15-08-2015
// Added configurable message delay in ms (delay between messages to controller)
// Changed login password field to type 'password'
// Fixed io pin settings for Dallas/DHT for inconsecutive pin configuration (ESP-01)
// Support for ThingsSpeak "controller" (webservice)
// R012 07-08-2015
// IMPORTANT NOTICE: this release needs ESP Package version 1.6.5-947-g39819f0, built on Jul 23, 2015)
// If udp port = 0 no actions!
// Used sprintf_P to save more RAM
// Added login page and admin password
// Added hardware custom gpio pin selection
// Added sanity check on BMP085 pressure values
// R011 12-07-2015
// Changed javascript link buttons into CSS button styled href links
// Fixed Main button, only worked on IE.
// Changed connectionFailures counting
// Reboot from main loop instead of web event callback
// Changed logging configuration
// BaudRate can be configured through webgui, defaults to 115200
// Added Serial.setDebugOutput(true) if serial loglevel = 4 (debug_more level)
// Added telnet protocol to send variable data to a Nodo Mega controller
// Added webgui I2C scanner
// Added webgui Wifi scanner
// Fixed bug in settingssave on devices
// Added delay(1) in Domoticz_sendData, while available loop
// R010 30-06-2015
// Changed freemem request in root web page
// Some memory reduced by eliminating globals
// Init MQTT at boot only if protocol is set to MQTT
// Added syslog level for detailed logging
// Added menu buttons in webgui and stuctured data as HTML tables
// R009 26-06-2015
// Changed switch pin from GPIO-0 to wired input pin 1
// Added config options for static IP/gateway/subnet
// Using LCD library instead of local functions
// Added MQTT library
// Added JSON parse library
// Needs Domoticz 2560 and Mosquitto 3.1.1 or higher
// Reduced EEPROM from 4096->1024 (needs a RAM buffer from same size!)
// Added basic logging to web interface
// R008 06-06-2015
// UDP listening port web configurable
// If UDP port enabled, also send IDX events to this UDP port
// Added Domotics lightswitch option, input on GPIO-0 pin.
// R007 01-06-2015
// use custom counter for WD instead of millis() (millis does not reset on ESP.Reset)
// Changed BAUDrate to 9600
// DomoticzGet <type>, <idx> test command (via serial)
// R006 23-05-2015
// Stored many constant strings to progmem
// delay(1) into http 'while' client check
// delay(10) in main loop instead of yield()
// DomoticzSend <type>,<idx>,<value> test command (via serial)
// Disabled analogRead, seems broken in g8cd3697 (use millis()/1000 as demo value!)
// R005 21-05-2015
// Some fixes to be compabtible with Arduino 1.6.4 using ESP board addon 1.6.4.-628-g545ffde
// R004 18-05-2015
// Fixed setting ip_octet to 0 on reset
@@ -29,80 +104,18 @@
// Delayed reboot on empty IP adress (in case of DHCP issue)
// Delayed reboot after 30 connection failures
// R005 21-05-2015
// Some fixes to be compabtible with Arduino 1.6.4 using ESP board addon 1.6.4.-628-g545ffde
// R003 06-05-2015
// Start AP mode if no connection, leave AP mode 30 seconds after succesfull connection
// Added option to set a fixed last octet of the ESP IP address (remaining config is still done with DHCP)
// This is the easiest way. You can still change subnet,gw,dns with DHCP but have a fixed IP
// This is convenient to control ESP with Domoticz http requests (relais, io expander, etc)
// Support for Domoticz multiple value sensor types (temp/hum/baro)
// Added support for pulsecounter
// R006 23-05-2015
// Stored many constant strings to progmem
// delay(1) into http 'while' client check
// delay(10) in main loop instead of yield()
// DomoticzSend <type>,<idx>,<value> test command (via serial)
// Disabled analogRead, seems broken in g8cd3697 (use millis()/1000 as demo value!)
// R002 02-05-2015
// Added configuration webinterface
// Start AP mode is ssid is not configured
// R007 01-06-2015
// use custom counter for WD instead of millis() (millis does not reset on ESP.Reset)
// Changed BAUDrate to 9600
// DomoticzGet <type>, <idx> test command (via serial)
// R008 06-06-2015
// UDP listening port web configurable
// If UDP port enabled, also send IDX events to this UDP port
// Added Domotics lightswitch option, input on GPIO-0 pin.
// R009 26-06-2015
// Changed switch pin from GPIO-0 to wired input pin 1
// Added config options for static IP/gateway/subnet
// Using LCD library instead of local functions
// Added MQTT library
// Added JSON parse library
// Needs Domoticz 2560 and Mosquitto 3.1.1 or higher
// Reduced EEPROM from 4096->1024 (needs a RAM buffer from same size!)
// Added basic logging to web interface
// R010 30-06-2015
// Changed freemem request in root web page
// Some memory reduced by eliminating globals
// Init MQTT at boot only if protocol is set to MQTT
// Added syslog level for detailed logging
// Added menu buttons in webgui and stuctured data as HTML tables
// R011 12-07-2015
// Changed javascript link buttons into CSS button styled href links
// Fixed Main button, only worked on IE.
// Changed connectionFailures counting
// Reboot from main loop instead of web event callback
// Changed logging configuration
// BaudRate can be configured through webgui, defaults to 115200
// Added Serial.setDebugOutput(true) if serial loglevel = 4 (debug_more level)
// Added telnet protocol to send variable data to a Nodo Mega controller
// Added webgui I2C scanner
// Added webgui Wifi scanner
// Fixed bug in settingssave on devices
// Added delay(1) in Domoticz_sendData, while available loop
// R012 07-08-2015
// IMPORTANT NOTICE: this release needs ESP Package version 1.6.5-947-g39819f0, built on Jul 23, 2015)
// If udp port = 0 no actions!
// Used sprintf_P to save more RAM
// Added login page and admin password
// Added hardware custom gpio pin selection
// Added sanity check on BMP085 pressure values
// R013 15-08-2015
// Added configurable message delay in ms (delay between messages to controller)
// Changed login password field to type 'password'
// Fixed io pin settings for Dallas/DHT for inconsecutive pin configuration (ESP-01)
// Support for ThingsSpeak "controller" (webservice)
// R014 20-08-2015
// Redesigned device configuration mechanisme
// Changed password timeout to 5 minutes
// Added direct GPIO output control without password request
// R015 22-08-2015
// Fixed a bug in DHT22 device
// Fixed a bug in setting for default delay
// Changed debug info
// Changed device tab, added more pin info and cancel button
// Fixed syslog loop bug
// R001 01-05-2015
// First 'stable' edition (meaning that it does not crash during boot of within one minute...)