mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-07-27 19:57:38 +00:00
Some optimizations
- v1.02 - some optimizations as requested by mvdbro - fixed JSON TaskDeviceValueDecimals handling - ArduinoJson Library v5.6.4 required (as used by stable R120) - parse for HTTP errors 400, 401 - moved on/off translation for SENSOR_TYPE_SWITCH/DIMMER to FHEM module
This commit is contained in:
@@ -6,13 +6,21 @@
|
||||
* Modified version of "Domoticz HTTP CPLUGIN"
|
||||
* Copyright 2016 dev0 (https://forum.fhem.de/index.php?action=profile;u=7465)
|
||||
* Release notes:
|
||||
- v1.0
|
||||
- changed switch and dimmer setreading cmds
|
||||
- v1.01
|
||||
- added json content to http requests
|
||||
- v1.02
|
||||
- some optimizations as requested by mvdbro
|
||||
- fixed JSON TaskDeviceValueDecimals handling
|
||||
- ArduinoJson Library v5.6.4 required (as used by stable R120)
|
||||
- parse for HTTP errors 400, 401
|
||||
- moved on/off translation for SENSOR_TYPE_SWITCH/DIMMER to FHEM module
|
||||
/******************************************************************************/
|
||||
|
||||
#define CPLUGIN_009
|
||||
#define CPLUGIN_ID_009 9
|
||||
#define CPLUGIN_NAME_009 "FHEM"
|
||||
#define CPLUGIN_NAME_009 "FHEM HTTP"
|
||||
|
||||
boolean CPlugin_009(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
@@ -24,6 +32,7 @@ boolean CPlugin_009(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
Protocol[++protocolCount].Number = CPLUGIN_ID_009;
|
||||
Protocol[protocolCount].usesMQTT = false;
|
||||
Protocol[protocolCount].usesTemplate = false;
|
||||
Protocol[protocolCount].usesAccount = true;
|
||||
Protocol[protocolCount].usesPassword = true;
|
||||
Protocol[protocolCount].defaultPort = 8383;
|
||||
@@ -38,36 +47,9 @@ boolean CPlugin_009(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case CPLUGIN_PROTOCOL_SEND:
|
||||
{
|
||||
String authHeader = "";
|
||||
if ((SecuritySettings.ControllerUser[0] != 0) && (SecuritySettings.ControllerPassword[0] != 0))
|
||||
{
|
||||
base64 encoder;
|
||||
String auth = SecuritySettings.ControllerUser;
|
||||
auth += ":";
|
||||
auth += SecuritySettings.ControllerPassword;
|
||||
authHeader = "Authorization: Basic " + encoder.encode(auth) + " \r\n";
|
||||
}
|
||||
|
||||
char log[80];
|
||||
boolean success = false;
|
||||
char host[20];
|
||||
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 using port %u"), "HTTP : connecting to ", host,Settings.ControllerPort);
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
|
||||
// Use WiFiClient class to create TCP connections
|
||||
WiFiClient client;
|
||||
if (!client.connect(host, Settings.ControllerPort))
|
||||
{
|
||||
connectionFailures++;
|
||||
strcpy_P(log, PSTR("HTTP : connection failed"));
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
return false;
|
||||
}
|
||||
statusLED(true);
|
||||
if (connectionFailures)
|
||||
connectionFailures--;
|
||||
if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0)
|
||||
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString);
|
||||
|
||||
// We now create a URI for the request
|
||||
String url = F("/fhem?cmd=");
|
||||
@@ -76,205 +58,143 @@ boolean CPlugin_009(byte function, struct EventStruct *event, String& string)
|
||||
DynamicJsonBuffer jsonBuffer;
|
||||
JsonObject& root = jsonBuffer.createObject();
|
||||
root["module"] = "ESPEasy";
|
||||
root["version"] = "1.0";
|
||||
root["version"] = "1.02";
|
||||
|
||||
// Create json objects
|
||||
// Create nested objects
|
||||
JsonObject& data = root.createNestedObject("data");
|
||||
JsonObject& ESP = data.createNestedObject("ESP");
|
||||
|
||||
ESP["name"] = Settings.Name;
|
||||
ESP["unit"] = Settings.Unit;
|
||||
ESP["version"] = Settings.Version;
|
||||
ESP["build"] = Settings.Build;
|
||||
ESP["sleep"] = Settings.deepSleep;
|
||||
|
||||
// embed IP, important if there is NAT/PAT
|
||||
char ipStr[20];
|
||||
IPAddress ip = WiFi.localIP();
|
||||
sprintf(ipStr, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
|
||||
ESP["ip"] = ipStr;
|
||||
|
||||
// Create other json objects
|
||||
// Create nested SENSOR json object
|
||||
JsonObject& SENSOR = data.createNestedObject("SENSOR");
|
||||
JsonObject& v0 = SENSOR.createNestedObject("v0");
|
||||
JsonObject& v1 = SENSOR.createNestedObject("v1");
|
||||
JsonObject& v2 = SENSOR.createNestedObject("v2");
|
||||
|
||||
switch (event->sensorType)
|
||||
byte valueCount = getValueCountFromSensorType(event->sensorType);
|
||||
char itemNames[valueCount][2];
|
||||
for (byte x = 0; x < valueCount; x++)
|
||||
{
|
||||
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
|
||||
url += F("setreading%20");
|
||||
url += Settings.Name;
|
||||
url += F("%20");
|
||||
url += ExtraTaskSettings.TaskDeviceValueNames[0];
|
||||
url += F("%20");
|
||||
url += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]);
|
||||
v0["deviceName"] = ExtraTaskSettings.TaskDeviceName;
|
||||
v0["valueName"] = ExtraTaskSettings.TaskDeviceValueNames[0];
|
||||
v0["value"] = UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0];
|
||||
v0["type"] = event->sensorType;
|
||||
break;
|
||||
|
||||
case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags)
|
||||
url += F("setreading%20");
|
||||
url += Settings.Name;
|
||||
url += F("%20");
|
||||
url += ExtraTaskSettings.TaskDeviceValueNames[0];
|
||||
url += F("%20");
|
||||
url += (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
|
||||
v0["deviceName"] = ExtraTaskSettings.TaskDeviceName;
|
||||
v0["valueName"] = ExtraTaskSettings.TaskDeviceValueNames[0];
|
||||
v0["value"] = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
|
||||
v0["type"] = event->sensorType;
|
||||
break;
|
||||
String s;
|
||||
url += F("setreading%20");
|
||||
url += Settings.Name;
|
||||
url += F("%20");
|
||||
url += ExtraTaskSettings.TaskDeviceValueNames[x];
|
||||
url += F("%20");
|
||||
|
||||
case SENSOR_TYPE_TEMP_HUM: // temp + hum + hum_stat, used for DHT11
|
||||
case SENSOR_TYPE_TEMP_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BMP085
|
||||
case SENSOR_TYPE_DUAL:
|
||||
// setreading #1
|
||||
url += F("setreading%20");
|
||||
url += Settings.Name;
|
||||
url += F("%20");
|
||||
url += ExtraTaskSettings.TaskDeviceValueNames[0];
|
||||
url += F("%20");
|
||||
url += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]);
|
||||
v0["deviceName"] = ExtraTaskSettings.TaskDeviceName;
|
||||
v0["valueName"] = ExtraTaskSettings.TaskDeviceValueNames[0];
|
||||
v0["value"] = UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0];
|
||||
v0["type"] = event->sensorType;
|
||||
// Each sensor value get an own object (0..n)
|
||||
sprintf(itemNames[x],"%d",x);
|
||||
JsonObject& val = SENSOR.createNestedObject(itemNames[x]);
|
||||
val["deviceName"] = ExtraTaskSettings.TaskDeviceName;
|
||||
val["valueName"] = ExtraTaskSettings.TaskDeviceValueNames[x];
|
||||
val["type"] = event->sensorType;
|
||||
|
||||
// setreading #2
|
||||
url += F("%3B");
|
||||
url += F("setreading%20");
|
||||
url += Settings.Name;
|
||||
url += F("%20");
|
||||
url += ExtraTaskSettings.TaskDeviceValueNames[1];
|
||||
url += F("%20");
|
||||
url += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]);
|
||||
v1["deviceName"] = ExtraTaskSettings.TaskDeviceName;
|
||||
v1["valueName"] = ExtraTaskSettings.TaskDeviceValueNames[1];
|
||||
v1["value"] = UserVar[event->BaseVarIndex +1],ExtraTaskSettings.TaskDeviceValueDecimals[1];
|
||||
v1["type"] = event->sensorType;
|
||||
break;
|
||||
if (event->sensorType == SENSOR_TYPE_LONG) {
|
||||
s = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
|
||||
url += s;
|
||||
val["value"] = s;
|
||||
|
||||
case SENSOR_TYPE_TEMP_HUM_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BME280
|
||||
case SENSOR_TYPE_TRIPLE:
|
||||
// setreading #1
|
||||
url += F("setreading%20");
|
||||
url += Settings.Name;
|
||||
url += F("%20");
|
||||
url += ExtraTaskSettings.TaskDeviceValueNames[0];
|
||||
url += F("%20");
|
||||
url += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]);
|
||||
v0["deviceName"] = ExtraTaskSettings.TaskDeviceName;
|
||||
v0["valueName"] = ExtraTaskSettings.TaskDeviceValueNames[0];
|
||||
v0["value"] = UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0];
|
||||
v0["type"] = event->sensorType;
|
||||
|
||||
// setreading #2
|
||||
url += F("%3B");
|
||||
url += F("setreading%20");
|
||||
url += Settings.Name;
|
||||
url += F("%20");
|
||||
url += ExtraTaskSettings.TaskDeviceValueNames[1];
|
||||
url += F("%20");
|
||||
url += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]);
|
||||
v1["deviceName"] = ExtraTaskSettings.TaskDeviceName;
|
||||
v1["valueName"] = ExtraTaskSettings.TaskDeviceValueNames[1];
|
||||
v1["value"] = UserVar[event->BaseVarIndex +1],ExtraTaskSettings.TaskDeviceValueDecimals[1];
|
||||
v1["type"] = event->sensorType;
|
||||
|
||||
// setreading #3
|
||||
url += F("%3B");
|
||||
url += "setreading%20";
|
||||
url += Settings.Name;
|
||||
url += F("%20");
|
||||
url += ExtraTaskSettings.TaskDeviceValueNames[2];
|
||||
url += F("%20");
|
||||
url += toString(UserVar[event->BaseVarIndex + 2],ExtraTaskSettings.TaskDeviceValueDecimals[2]);
|
||||
v2["deviceName"] = ExtraTaskSettings.TaskDeviceName;
|
||||
v2["valueName"] = ExtraTaskSettings.TaskDeviceValueNames[2];
|
||||
v2["value"] = UserVar[event->BaseVarIndex +2],ExtraTaskSettings.TaskDeviceValueDecimals[2];
|
||||
v2["type"] = event->sensorType;
|
||||
break;
|
||||
|
||||
case SENSOR_TYPE_SWITCH:
|
||||
url += F("setreading%20");
|
||||
url += Settings.Name;
|
||||
url += F("%20");
|
||||
url += ExtraTaskSettings.TaskDeviceValueNames[0];
|
||||
url += F("%20");
|
||||
v0["deviceName"] = ExtraTaskSettings.TaskDeviceName;
|
||||
v0["valueName"] = ExtraTaskSettings.TaskDeviceValueNames[0];
|
||||
v0["type"] = event->sensorType;
|
||||
if (UserVar[event->BaseVarIndex] == 0) {
|
||||
url += "off";
|
||||
v0["value"] = "off";
|
||||
} else {
|
||||
url += "on";
|
||||
v0["value"] = "on";
|
||||
}
|
||||
break;
|
||||
|
||||
case SENSOR_TYPE_DIMMER:
|
||||
url += F("setreading%20");
|
||||
url += Settings.Name;
|
||||
url += F("%20");
|
||||
url += ExtraTaskSettings.TaskDeviceValueNames[0];
|
||||
url += F("%20");
|
||||
v0["deviceName"] = ExtraTaskSettings.TaskDeviceName;
|
||||
v0["valueName"] = ExtraTaskSettings.TaskDeviceValueNames[0];
|
||||
v0["type"] = event->sensorType;
|
||||
if (UserVar[event->BaseVarIndex] == 0) {
|
||||
url += "off";
|
||||
v0["value"] = "off";
|
||||
} else {
|
||||
url += UserVar[event->BaseVarIndex];
|
||||
v0["value"] = UserVar[event->BaseVarIndex];
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
url.toCharArray(log, 80);
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
|
||||
char buffer[2048];
|
||||
root.printTo(buffer, sizeof(buffer));
|
||||
int len = root.measureLength();
|
||||
|
||||
// This will send the request to the server
|
||||
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
|
||||
"Content-Length: "+ len + "\r\n" +
|
||||
"Host: " + host + "\r\n" + authHeader +
|
||||
"Connection: close\r\n\r\n"
|
||||
+ buffer);
|
||||
|
||||
unsigned long timer = millis() + 200;
|
||||
while (!client.available() && millis() < timer)
|
||||
delay(1);
|
||||
|
||||
// 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, 80);
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
if (line.substring(0, 15) == "HTTP/1.1 200 OK")
|
||||
{
|
||||
strcpy_P(log, PSTR("HTTP : Success"));
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
success = true;
|
||||
} else { // All other sensor types
|
||||
s = toString(UserVar[event->BaseVarIndex + x], ExtraTaskSettings.TaskDeviceValueDecimals[x]);
|
||||
url += s;
|
||||
val["value"] = s;
|
||||
}
|
||||
delay(1);
|
||||
|
||||
// Split FHEM commands by ";"
|
||||
if (x < valueCount-1)
|
||||
url += F("%3B");
|
||||
}
|
||||
strcpy_P(log, PSTR("HTTP : closing connection"));
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
|
||||
client.flush();
|
||||
client.stop();
|
||||
|
||||
// Create json buffer
|
||||
char buffer[root.measureLength() +1];
|
||||
root.printTo(buffer, sizeof(buffer));
|
||||
// Push data to server
|
||||
FHEMHTTPsend(url, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// FHEM HTTP request
|
||||
//********************************************************************************
|
||||
boolean FHEMHTTPsend(String url, char* buffer)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
String authHeader = "";
|
||||
if ((SecuritySettings.ControllerUser[0] != 0) && (SecuritySettings.ControllerPassword[0] != 0)) {
|
||||
base64 encoder;
|
||||
String auth = SecuritySettings.ControllerUser;
|
||||
auth += ":";
|
||||
auth += SecuritySettings.ControllerPassword;
|
||||
authHeader = "Authorization: Basic " + encoder.encode(auth) + " \r\n";
|
||||
}
|
||||
|
||||
char log[80];
|
||||
url.toCharArray(log, 80);
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
|
||||
char host[20];
|
||||
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 using port %u"), "HTTP : connecting to ", host,Settings.ControllerPort);
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
|
||||
// Use WiFiClient class to create TCP connections
|
||||
WiFiClient client;
|
||||
if (!client.connect(host, Settings.ControllerPort)) {
|
||||
connectionFailures++;
|
||||
strcpy_P(log, PSTR("HTTP : connection failed"));
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
return false;
|
||||
}
|
||||
|
||||
statusLED(true);
|
||||
if (connectionFailures)
|
||||
connectionFailures--;
|
||||
|
||||
// This will send the request to the server
|
||||
int len = strlen(buffer);
|
||||
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
|
||||
"Content-Length: "+ len + "\r\n" +
|
||||
"Host: " + host + "\r\n" + authHeader +
|
||||
"Connection: close\r\n\r\n"
|
||||
+ buffer);
|
||||
|
||||
unsigned long timer = millis() + 200;
|
||||
while (!client.available() && millis() < timer)
|
||||
delay(1);
|
||||
|
||||
// Read all the lines of the reply from server and print them to Serial
|
||||
while (client.available()) {
|
||||
String line = client.readStringUntil('\n');
|
||||
String helper = line;
|
||||
line.toCharArray(log, 80);
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
if (line.substring(0, 15) == "HTTP/1.1 200 OK") {
|
||||
strcpy_P(log, PSTR("HTTP : Success"));
|
||||
success = true;
|
||||
}
|
||||
else if (line.substring(0, 24) == "HTTP/1.1 400 Bad Request") {
|
||||
strcpy_P(log, PSTR("HTTP : Unauthorized"));
|
||||
}
|
||||
else if (line.substring(0, 25) == "HTTP/1.1 401 Unauthorized") {
|
||||
strcpy_P(log, PSTR("HTTP : Unauthorized"));
|
||||
}
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
delay(1);
|
||||
}
|
||||
strcpy_P(log, PSTR("HTTP : closing connection"));
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
client.flush();
|
||||
client.stop();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user