Added additional checks for firmware updates #157 Added endpoints for setting current position #156

This commit is contained in:
Robert Strouse 2023-09-24 15:12:15 -07:00
parent a6c7601458
commit a823d2349a
11 changed files with 273 additions and 18 deletions

View file

@ -3,7 +3,7 @@
#ifndef configsettings_h #ifndef configsettings_h
#define configsettings_h #define configsettings_h
#define FW_VERSION "v2.1.7" #define FW_VERSION "v2.1.8"
enum DeviceStatus { enum DeviceStatus {
DS_OK = 0, DS_OK = 0,
DS_ERROR = 1, DS_ERROR = 1,

View file

@ -126,6 +126,24 @@ void MQTTClass::receive(const char *topic, byte*payload, uint32_t length) {
if(val > 0) shade->sendCommand(somfy_commands::SunFlag); if(val > 0) shade->sendCommand(somfy_commands::SunFlag);
else shade->sendCommand(somfy_commands::Flag); else shade->sendCommand(somfy_commands::Flag);
} }
else if(strncmp(command, "position", sizeof(command)) == 0) {
if(val >= 0 && val <= 100) {
shade->target = shade->currentPos = (float)val;
shade->emitState();
}
}
else if(strncmp(command, "tiltPosition", sizeof(command)) == 0) {
if(val >= 0 && val <= 100) {
shade->tiltTarget = shade->currentTiltPos = (float)val;
shade->emitState();
}
}
else if(strncmp(command, "sunny", sizeof(command)) == 0) {
if(val >= 0) shade->sendSensorCommand(-1, val, shade->repeats);
}
else if(strncmp(command, "windy", sizeof(command)) == 0) {
if(val >= 0) shade->sendSensorCommand(val, -1, shade->repeats);
}
} }
} }
else if(strncmp(entityType, "groups", sizeof(entityType)) == 0) { else if(strncmp(entityType, "groups", sizeof(entityType)) == 0) {
@ -146,6 +164,12 @@ void MQTTClass::receive(const char *topic, byte*payload, uint32_t length) {
else else
group->sendCommand(somfy_commands::SunFlag); group->sendCommand(somfy_commands::SunFlag);
} }
else if(strncmp(command, "sunny", sizeof(command)) == 0) {
if(val >= 0) group->sendSensorCommand(-1, val, group->repeats);
}
else if(strncmp(command, "windy", sizeof(command)) == 0) {
if(val >= 0) group->sendSensorCommand(val, -1, group->repeats);
}
} }
} }
} }
@ -172,7 +196,15 @@ bool MQTTClass::connect() {
this->subscribe("shades/+/mypos/set"); this->subscribe("shades/+/mypos/set");
this->subscribe("shades/+/myTiltPos/set"); this->subscribe("shades/+/myTiltPos/set");
this->subscribe("shades/+/sunFlag/set"); this->subscribe("shades/+/sunFlag/set");
this->subscribe("shades/+/sunny/set");
this->subscribe("shades/+/windy/set");
this->subscribe("shades/+/position/set");
this->subscribe("shades/+/tiltPosition/set");
this->subscribe("groups/+/direction/set"); this->subscribe("groups/+/direction/set");
this->subscribe("groups/+/sunFlag/set");
this->subscribe("groups/+/sunny/set");
this->subscribe("groups/+/windy/set");
mqttClient.setCallback(MQTTClass::receive); mqttClient.setCallback(MQTTClass::receive);
this->lastConnect = millis(); this->lastConnect = millis();
return true; return true;
@ -198,6 +230,14 @@ bool MQTTClass::disconnect() {
this->unsubscribe("shades/+/myTiltPos/set"); this->unsubscribe("shades/+/myTiltPos/set");
this->unsubscribe("shades/+/sunFlag/set"); this->unsubscribe("shades/+/sunFlag/set");
this->unsubscribe("groups/+/direction/set"); this->unsubscribe("groups/+/direction/set");
this->unsubscribe("shades/+/sunny/set");
this->unsubscribe("shades/+/windy/set");
this->unsubscribe("shades/+/position/set");
this->unsubscribe("shades/+/tiltPosition/set");
this->unsubscribe("groups/+/direction/set");
this->unsubscribe("groups/+/sunFlag/set");
this->unsubscribe("groups/+/sunny/set");
this->unsubscribe("groups/+/windy/set");
mqttClient.disconnect(); mqttClient.disconnect();
} }
return true; return true;

View file

@ -143,7 +143,6 @@ void somfy_frame_t::decodeFrame(byte* frame) {
// We reuse this memory address so we must reset the processed // We reuse this memory address so we must reset the processed
// flag. This will ensure we can see frames on the first beat. // flag. This will ensure we can see frames on the first beat.
this->processed = false; this->processed = false;
Serial.println("Processed set to false");
// Pull in the data for an 80-bit step command. // Pull in the data for an 80-bit step command.
if(this->cmd == somfy_commands::StepDown) this->cmd = (somfy_commands)((decoded[1] >> 4) | ((decoded[8] & 0x08) << 4)); if(this->cmd == somfy_commands::StepDown) this->cmd = (somfy_commands)((decoded[1] >> 4) | ((decoded[8] & 0x08) << 4));
this->rollingCode = decoded[3] + (decoded[2] << 8); this->rollingCode = decoded[3] + (decoded[2] << 8);
@ -856,6 +855,7 @@ void SomfyShade::checkMovement() {
&& this->noSunStart && this->noSunStart
&& (curTime - this->noSunStart) >= SOMFY_NO_SUN_TIMEOUT) && (curTime - this->noSunStart) >= SOMFY_NO_SUN_TIMEOUT)
{ {
if(this->tiltType == tilt_types::tiltonly) this->tiltTarget = 0.0f;
this->target = 0.0f; this->target = 0.0f;
this->noSunDone = true; this->noSunDone = true;
Serial.printf("[%u] No Sun -> done\r\n", this->shadeId); Serial.printf("[%u] No Sun -> done\r\n", this->shadeId);
@ -867,6 +867,7 @@ void SomfyShade::checkMovement() {
&& this->windStart && this->windStart
&& (curTime - this->windStart) >= SOMFY_WIND_TIMEOUT) && (curTime - this->windStart) >= SOMFY_WIND_TIMEOUT)
{ {
if(this->tiltType == tilt_types::tiltonly) this->tiltTarget = 0.0f;
this->target = 0.0f; this->target = 0.0f;
this->windDone = true; this->windDone = true;
Serial.printf("[%u] Wind -> done\r\n", this->shadeId); Serial.printf("[%u] Wind -> done\r\n", this->shadeId);
@ -2635,6 +2636,32 @@ somfy_commands SomfyRemote::transformCommand(somfy_commands cmd) {
} }
return cmd; return cmd;
} }
void SomfyRemote::sendSensorCommand(int8_t isWindy, int8_t isSunny, uint8_t repeat) {
uint8_t flags = (this->flags >> 4) & 0x0F;
if(isWindy > 0) flags |= 0x01;
if(isSunny > 0) flags |= 0x02;
if(isWindy == 0) flags &= ~0x01;
if(isSunny == 0) flags &= ~0x02;
// Now ship this off as an 80 bit command.
this->lastFrame.remoteAddress = this->getRemoteAddress();
this->lastFrame.repeats = repeat;
this->lastFrame.bitLength = this->bitLength;
this->lastFrame.rollingCode = (uint16_t)flags;
this->lastFrame.encKey = 160; // Sensor commands are always encryption code 160.
this->lastFrame.cmd = somfy_commands::Sensor;
this->lastFrame.processed = false;
Serial.print("CMD:");
Serial.print(translateSomfyCommand(this->lastFrame.cmd));
Serial.print(" ADDR:");
Serial.print(this->lastFrame.remoteAddress);
Serial.print(" RCODE:");
Serial.print(this->lastFrame.rollingCode);
Serial.print(" REPEAT:");
Serial.println(repeat);
somfy.sendFrame(this->lastFrame, repeat);
somfy.processFrame(this->lastFrame, true);
}
void SomfyRemote::sendCommand(somfy_commands cmd) { this->sendCommand(cmd, this->repeats); } void SomfyRemote::sendCommand(somfy_commands cmd) { this->sendCommand(cmd, this->repeats); }
void SomfyRemote::sendCommand(somfy_commands cmd, uint8_t repeat) { void SomfyRemote::sendCommand(somfy_commands cmd, uint8_t repeat) {
this->lastFrame.rollingCode = this->getNextRollingCode(); this->lastFrame.rollingCode = this->getNextRollingCode();

View file

@ -201,6 +201,7 @@ class SomfyRemote {
void setLight(bool bHasLight); void setLight(bool bHasLight);
virtual void sendCommand(somfy_commands cmd); virtual void sendCommand(somfy_commands cmd);
virtual void sendCommand(somfy_commands cmd, uint8_t repeat); virtual void sendCommand(somfy_commands cmd, uint8_t repeat);
void sendSensorCommand(int8_t isWindy, int8_t isSunny, uint8_t repeat);
void repeatFrame(uint8_t repeat); void repeatFrame(uint8_t repeat);
somfy_commands transformCommand(somfy_commands cmd); somfy_commands transformCommand(somfy_commands cmd);
}; };

Binary file not shown.

Binary file not shown.

161
Web.cpp
View file

@ -696,6 +696,133 @@ void Web::handleDiscovery(WebServer &server) {
else else
server.send(500, _encoding_text, "Invalid http method"); server.send(500, _encoding_text, "Invalid http method");
} }
void Web::handleSetPositions(WebServer &server) {
webServer.sendCORSHeaders(server);
if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; }
HTTPMethod method = apiServer.method();
uint8_t shadeId = (server.hasArg("shadeId")) ? atoi(server.arg("shadeId").c_str()) : 255;
int8_t pos = (server.hasArg("position")) ? atoi(server.arg("position").c_str()) : -1;
int8_t tiltPos = (server.hasArg("tiltPosition")) ? atoi(server.arg("tiltPosition").c_str()) : -1;
if(server.hasArg("plain")) {
DynamicJsonDocument doc(512);
DeserializationError err = deserializeJson(doc, server.arg("plain"));
if (err) {
switch (err.code()) {
case DeserializationError::InvalidInput:
server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"Invalid JSON payload\"}"));
break;
case DeserializationError::NoMemory:
server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"Out of memory parsing JSON\"}"));
break;
default:
server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"General JSON Deserialization failed\"}"));
break;
}
}
else {
JsonObject obj = doc.as<JsonObject>();
if(obj.containsKey("shadeId")) shadeId = obj["shadeId"];
if(obj.containsKey("position")) pos = obj["position"];
if(obj.containsKey("tiltPosition")) tiltPos = obj["tiltPosition"];
}
}
if(shadeId != 255) {
SomfyShade *shade = somfy.getShadeById(shadeId);
if(shade) {
if(pos >= 0) shade->target = shade->currentPos = pos;
if(tiltPos >= 0 && shade->tiltType != tilt_types::none) shade->tiltTarget = shade->currentTiltPos = tiltPos;
shade->emitState();
DynamicJsonDocument sdoc(2048);
JsonObject sobj = sdoc.to<JsonObject>();
shade->toJSON(sobj);
serializeJson(sdoc, g_content);
server.send(200, _encoding_json, g_content);
}
else
server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"An invalid shadeId was provided\"}"));
}
else {
server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"shadeId was not provided\"}"));
}
}
void Web::handleSetSensor(WebServer &server) {
webServer.sendCORSHeaders(server);
if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; }
HTTPMethod method = apiServer.method();
uint8_t shadeId = (server.hasArg("shadeId")) ? atoi(server.arg("shadeId").c_str()) : 255;
uint8_t groupId = (server.hasArg("groupId")) ? atoi(server.arg("groupId").c_str()) : 255;
int8_t sunny = (server.hasArg("sunny")) ? toBoolean(server.arg("sunny").c_str(), false) ? 1 : 0 : -1;
int8_t windy = (server.hasArg("windy")) ? atoi(server.arg("windy").c_str()) : -1;
int8_t repeat = (server.hasArg("repeat")) ? atoi(server.arg("repeat").c_str()) : -1;
if(server.hasArg("plain")) {
DynamicJsonDocument doc(512);
DeserializationError err = deserializeJson(doc, server.arg("plain"));
if (err) {
switch (err.code()) {
case DeserializationError::InvalidInput:
server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"Invalid JSON payload\"}"));
break;
case DeserializationError::NoMemory:
server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"Out of memory parsing JSON\"}"));
break;
default:
server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"General JSON Deserialization failed\"}"));
break;
}
}
else {
JsonObject obj = doc.as<JsonObject>();
if(obj.containsKey("shadeId")) shadeId = obj["shadeId"].as<uint8_t>();
if(obj.containsKey("groupId")) groupId = obj["groupId"].as<uint8_t>();
if(obj.containsKey("sunny")) {
if(obj["sunny"].is<bool>())
sunny = obj["sunny"].as<bool>() ? 1 : 0;
else
sunny = obj["sunny"].as<int8_t>();
}
if(obj.containsKey("windy")) {
if(obj["windy"].is<bool>())
windy = obj["windy"].as<bool>() ? 1 : 0;
else
windy = obj["windy"].as<int8_t>();
}
if(obj.containsKey("repeat")) repeat = obj["repeat"].as<uint8_t>();
}
}
if(shadeId != 255) {
SomfyShade *shade = somfy.getShadeById(shadeId);
if(shade) {
shade->sendSensorCommand(windy, sunny, repeat >= 0 ? (uint8_t)repeat : shade->repeats);
shade->emitState();
DynamicJsonDocument sdoc(2048);
JsonObject sobj = sdoc.to<JsonObject>();
shade->toJSON(sobj);
serializeJson(sdoc, g_content);
server.send(200, _encoding_json, g_content);
}
else
server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"An invalid shadeId was provided\"}"));
}
else if(groupId != 255) {
SomfyGroup *group = somfy.getGroupById(groupId);
if(group) {
group->sendSensorCommand(windy, sunny, repeat >= 0 ? (uint8_t)repeat : group->repeats);
group->emitState();
DynamicJsonDocument sdoc(2048);
JsonObject sobj = sdoc.to<JsonObject>();
group->toJSON(sobj);
serializeJson(sdoc, g_content);
server.send(200, _encoding_json, g_content);
}
else
server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"An invalid groupId was provided\"}"));
}
else {
server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"shadeId was not provided\"}"));
}
}
void Web::handleNotFound(WebServer &server) { void Web::handleNotFound(WebServer &server) {
HTTPMethod method = server.method(); HTTPMethod method = server.method();
Serial.printf("Request %s 404-%d ", server.uri().c_str(), method); Serial.printf("Request %s 404-%d ", server.uri().c_str(), method);
@ -743,13 +870,16 @@ void Web::begin() {
apiServer.on("/repeatCommand", []() { webServer.handleRepeatCommand(apiServer); }); apiServer.on("/repeatCommand", []() { webServer.handleRepeatCommand(apiServer); });
apiServer.on("/shade", HTTP_GET, [] () { webServer.handleShade(apiServer); }); apiServer.on("/shade", HTTP_GET, [] () { webServer.handleShade(apiServer); });
apiServer.on("/group", HTTP_GET, [] () { webServer.handleGroup(apiServer); }); apiServer.on("/group", HTTP_GET, [] () { webServer.handleGroup(apiServer); });
apiServer.on("/setPositions", []() { webServer.handleSetPositions(apiServer); });
apiServer.on("/setSensor", []() { webServer.handleSetSensor(apiServer); });
// Web Interface // Web Interface
server.on("/tiltCommand", []() { webServer.handleTiltCommand(server); }); server.on("/tiltCommand", []() { webServer.handleTiltCommand(server); });
server.on("/repeatCommand", []() { webServer.handleRepeatCommand(server); }); server.on("/repeatCommand", []() { webServer.handleRepeatCommand(server); });
server.on("/shadeCommand", []() { webServer.handleShadeCommand(server); }); server.on("/shadeCommand", []() { webServer.handleShadeCommand(server); });
server.on("/groupCommand", []() { webServer.handleGroupCommand(server); }); server.on("/groupCommand", []() { webServer.handleGroupCommand(server); });
server.on("/setPositions", []() { webServer.handleSetPositions(server); });
server.on("/setSensor", []() { webServer.handleSetSensor(server); });
server.on("/upnp.xml", []() { SSDP.schema(server.client()); }); server.on("/upnp.xml", []() { SSDP.schema(server.client()); });
server.on("/", []() { webServer.handleStreamFile(server, "/index.html", _encoding_html); }); server.on("/", []() { webServer.handleStreamFile(server, "/index.html", _encoding_html); });
server.on("/login", []() { webServer.handleLogin(server); }); server.on("/login", []() { webServer.handleLogin(server); });
@ -1623,14 +1753,15 @@ void Web::begin() {
if (Update.hasError()) if (Update.hasError())
server.send(500, _encoding_json, "{\"status\":\"ERROR\",\"desc\":\"Error updating firmware: \"}"); server.send(500, _encoding_json, "{\"status\":\"ERROR\",\"desc\":\"Error updating firmware: \"}");
else else
server.send(200, _encoding_json, "{\"status\":\"ERROR\",\"desc\":\"Updating firmware: \"}"); server.send(200, _encoding_json, "{\"status\":\"SUCCESS\",\"desc\":\"Successfully updated firmware\"}");
rebootDelay.reboot = true; rebootDelay.reboot = true;
rebootDelay.rebootTime = millis() + 500; rebootDelay.rebootTime = millis() + 500;
}, []() { }, []() {
HTTPUpload& upload = server.upload(); HTTPUpload& upload = server.upload();
if (upload.status == UPLOAD_FILE_START) { if (upload.status == UPLOAD_FILE_START) {
webServer.uploadSuccess = false; webServer.uploadSuccess = false;
Serial.printf("Update: %s\n", upload.filename.c_str()); Serial.printf("Update: %s - %d\n", upload.filename.c_str(), upload.totalSize);
//if(!Update.begin(upload.totalSize, U_SPIFFS)) {
if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size
Update.printError(Serial); Update.printError(Serial);
} }
@ -1639,10 +1770,16 @@ void Web::begin() {
mqtt.end(); mqtt.end();
} }
} }
else if(upload.status == UPLOAD_FILE_ABORTED) {
Serial.printf("Upload of %s aborted\n", upload.filename.c_str());
Update.abort();
}
else if (upload.status == UPLOAD_FILE_WRITE) { else if (upload.status == UPLOAD_FILE_WRITE) {
/* flashing firmware to ESP*/ /* flashing firmware to ESP*/
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
Update.printError(Serial); Update.printError(Serial);
Serial.printf("Upload of %s aborted invalid size %d\n", upload.filename.c_str(), upload.currentSize);
Update.abort();
} }
} }
else if (upload.status == UPLOAD_FILE_END) { else if (upload.status == UPLOAD_FILE_END) {
@ -1683,14 +1820,18 @@ void Web::begin() {
webServer.sendCORSHeaders(server); webServer.sendCORSHeaders(server);
if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; }
server.sendHeader("Connection", "close"); server.sendHeader("Connection", "close");
server.send(200, _encoding_json, "{\"status\":\"ERROR\",\"desc\":\"Updating Application: \"}"); if (Update.hasError())
server.send(500, _encoding_json, "{\"status\":\"ERROR\",\"desc\":\"Error updating application: \"}");
else
server.send(200, _encoding_json, "{\"status\":\"SUCCESS\",\"desc\":\"Successfully updated application\"}");
rebootDelay.reboot = true; rebootDelay.reboot = true;
rebootDelay.rebootTime = millis() + 500; rebootDelay.rebootTime = millis() + 500;
}, []() { }, []() {
HTTPUpload& upload = server.upload(); HTTPUpload& upload = server.upload();
if (upload.status == UPLOAD_FILE_START) { if (upload.status == UPLOAD_FILE_START) {
webServer.uploadSuccess = false; webServer.uploadSuccess = false;
Serial.printf("Update: %s\n", upload.filename.c_str()); Serial.printf("Update: %s %d\n", upload.filename.c_str(), upload.totalSize);
//if(!Update.begin(upload.totalSize, U_SPIFFS)) {
if (!Update.begin(UPDATE_SIZE_UNKNOWN, U_SPIFFS)) { //start with max available size and tell it we are updating the file system. if (!Update.begin(UPDATE_SIZE_UNKNOWN, U_SPIFFS)) { //start with max available size and tell it we are updating the file system.
Update.printError(Serial); Update.printError(Serial);
} }
@ -1699,10 +1840,17 @@ void Web::begin() {
mqtt.end(); mqtt.end();
} }
} }
else if(upload.status == UPLOAD_FILE_ABORTED) {
Serial.printf("Upload of %s aborted\n", upload.filename.c_str());
Update.abort();
somfy.commit();
}
else if (upload.status == UPLOAD_FILE_WRITE) { else if (upload.status == UPLOAD_FILE_WRITE) {
/* flashing littlefs to ESP*/ /* flashing littlefs to ESP*/
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
Update.printError(Serial); Update.printError(Serial);
Serial.printf("Upload of %s aborted invalid size %d\n", upload.filename.c_str(), upload.currentSize);
Update.abort();
} }
} }
else if (upload.status == UPLOAD_FILE_END) { else if (upload.status == UPLOAD_FILE_END) {
@ -1712,6 +1860,7 @@ void Web::begin() {
somfy.commit(); somfy.commit();
} }
else { else {
somfy.commit();
Update.printError(Serial); Update.printError(Serial);
} }
} }

2
Web.h
View file

@ -22,6 +22,8 @@ class Web {
void handleNotFound(WebServer &server); void handleNotFound(WebServer &server);
void handleShade(WebServer &server); void handleShade(WebServer &server);
void handleGroup(WebServer &server); void handleGroup(WebServer &server);
void handleSetPositions(WebServer &server);
void handleSetSensor(WebServer &server);
void begin(); void begin();
void loop(); void loop();
void end(); void end();

View file

@ -1 +1 @@
2.1.7 2.1.8

View file

@ -3,11 +3,11 @@
<head> <head>
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="UTF-8"> <meta charset="UTF-8">
<link rel="stylesheet" href="main.css?v=2.1.7" type="text/css" /> <link rel="stylesheet" href="main.css?v=2.1.8" type="text/css" />
<link rel="stylesheet" href="widgets.css?v=2.1.7" type="text/css" /> <link rel="stylesheet" href="widgets.css?v=2.1.8" type="text/css" />
<link rel="stylesheet" href="icons.css?v=2.1.7" type="text/css" /> <link rel="stylesheet" href="icons.css?v=2.1.8" type="text/css" />
<link rel="icon" type="image/png" href="favicon.png" /> <link rel="icon" type="image/png" href="favicon.png" />
<script type="text/javascript" src="index.js?v=2.1.7"></script> <script type="text/javascript" src="index.js?v=2.1.8"></script>
</head> </head>
<body> <body>
<div id="divContainer" class="container main" data-auth="false"> <div id="divContainer" class="container main" data-auth="false">
@ -611,6 +611,24 @@
<div class="button-outline" style="width:127px;text-align:center;border-radius:33%;font-size:2em;padding:10px;" data-cmd="Flag" onmousedown="somfy.sendVRCommand(this);" ontouchstart="somfy.sendVRCommand(this);"><div class="button-sunflag" data-on="false" style="margin:0px;"><i class="icss-sun-c" style="background:transparent;"></i><i class="icss-sun-o" style="left:0px;color:white;"></i></div><span>off</span></div> <div class="button-outline" style="width:127px;text-align:center;border-radius:33%;font-size:2em;padding:10px;" data-cmd="Flag" onmousedown="somfy.sendVRCommand(this);" ontouchstart="somfy.sendVRCommand(this);"><div class="button-sunflag" data-on="false" style="margin:0px;"><i class="icss-sun-c" style="background:transparent;"></i><i class="icss-sun-o" style="left:0px;color:white;"></i></div><span>off</span></div>
</div> </div>
</div> </div>
<div class="vr-button">
<span>
<span>Sensor</span>
<span style="display:inline-block;vertical-align:middle;margin-left:14px;">
<span style="display:block">
<input id="cbSunny" type="checkbox" data-bind="sunny" style="display:inline-block;" />
<label for="cbSunny" style="display:inline-block;cursor:pointer;">Sunny</label>
</span>
<span style="display:block">
<input id="cbWindy" type="checkbox" data-bind="windy" style="display:inline-block;" />
<label for="cbWindy" style="display:inline-block;cursor:pointer;">Windy</label>
</span>
</span>
</span>
<div>
<div class="button-outline" style="width:127px;text-align:center;border-radius:33%;font-size:2em;padding:10px;" data-cmd="Sensor" onmousedown="somfy.sendVRCommand(this);" ontouchstart="somfy.sendVRCommand(this);"><div class="button-sunflag" data-on="false" style="margin:0px;"></div><span>send</span></div>
</div>
</div>
</div> </div>
</div> </div>
<div id="divRadioSettings" style="display:none;"> <div id="divRadioSettings" style="display:none;">

View file

@ -149,7 +149,7 @@ Number.prototype.fmt = function (format, empty) {
if (rd.length === 0 && rw.length === 0) return ''; if (rd.length === 0 && rw.length === 0) return '';
return pfx + rw + rd + sfx; return pfx + rw + rd + sfx;
}; };
var baseUrl = window.location.protocol === 'file:' ? 'http://ESPSomfyRTS.local' : ''; var baseUrl = window.location.protocol === 'file:' ? 'http://ESPSomfyRTS' : '';
//var baseUrl = ''; //var baseUrl = '';
function makeBool(val) { function makeBool(val) {
if (typeof val === 'boolean') return val; if (typeof val === 'boolean') return val;
@ -519,6 +519,7 @@ async function initSockets() {
} }
else { else {
(async () => { (async () => {
ui.clearErrors();
await general.loadGeneral(); await general.loadGeneral();
await wifi.loadNetwork(); await wifi.loadNetwork();
await somfy.loadSomfy(); await somfy.loadSomfy();
@ -1200,7 +1201,7 @@ var security = new Security();
class General { class General {
initialized = false; initialized = false;
appVersion = 'v2.1.7'; appVersion = 'v2.1.8';
reloadApp = false; reloadApp = false;
init() { init() {
if (this.initialized) return; if (this.initialized) return;
@ -3415,6 +3416,8 @@ class Somfy {
address: opt.getAttribute('data-address'), address: opt.getAttribute('data-address'),
cmd: el.getAttribute('data-cmd') cmd: el.getAttribute('data-cmd')
}; };
ui.fromElement(el.parentElement.parentElement, o);
console.log(o);
switch (o.type) { switch (o.type) {
case 'shade': case 'shade':
o.shadeId = parseInt(opt.getAttribute('data-shadeId'), 10); o.shadeId = parseInt(opt.getAttribute('data-shadeId'), 10);
@ -3432,17 +3435,28 @@ class Somfy {
} }
if (err) return; if (err) return;
if (mouseDown) { if (mouseDown) {
if (o.type === 'group') if (o.cmd === 'Sensor')
somfy.sendSetSensor(o);
else if (o.type === 'group')
somfy.sendGroupRepeat(o.groupId, o.cmd, null, fnRepeatCommand); somfy.sendGroupRepeat(o.groupId, o.cmd, null, fnRepeatCommand);
else else
somfy.sendCommandRepeat(o.shadeId, o.cmd, null, fnRepeatCommand); somfy.sendCommandRepeat(o.shadeId, o.cmd, null, fnRepeatCommand);
} }
} }
if (o.type === 'group') if (o.cmd === 'Sensor') {
somfy.sendSetSensor(o);
}
else if (o.type === 'group')
somfy.sendGroupCommand(o.groupId, o.cmd, null, (err, group) => { fnRepeatCommand(err, group); }); somfy.sendGroupCommand(o.groupId, o.cmd, null, (err, group) => { fnRepeatCommand(err, group); });
else else
somfy.sendCommand(o.shadeId, o.cmd, null, (err, shade) => { fnRepeatCommand(err, shade); }); somfy.sendCommand(o.shadeId, o.cmd, null, (err, shade) => { fnRepeatCommand(err, shade); });
} }
sendSetSensor(obj, cb) {
putJSON('/setSensor', obj, (err, device) => {
if (typeof cb === 'function') cb(err, device);
});
}
sendGroupCommand(groupId, command, repeat, cb) { sendGroupCommand(groupId, command, repeat, cb) {
console.log(`Sending Group command ${groupId}-${command}`); console.log(`Sending Group command ${groupId}-${command}`);
let obj = { groupId: groupId }; let obj = { groupId: groupId };
@ -4026,7 +4040,6 @@ class Firmware {
let prog = el.querySelector('div[id="progFileUpload"]'); let prog = el.querySelector('div[id="progFileUpload"]');
prog.style.display = ''; prog.style.display = '';
btnSelectFile.style.visibility = 'hidden'; btnSelectFile.style.visibility = 'hidden';
let xhr = new XMLHttpRequest(); let xhr = new XMLHttpRequest();
//xhr.open('POST', service, true); //xhr.open('POST', service, true);
xhr.open('POST', baseUrl.length > 0 ? `${baseUrl}${service}` : service, true); xhr.open('POST', baseUrl.length > 0 ? `${baseUrl}${service}` : service, true);
@ -4057,6 +4070,11 @@ class Firmware {
} }
}; };
xhr.send(formData); xhr.send(formData);
btnCancel.addEventListener('click', (e) => {
console.log('Cancel clicked');
xhr.abort();
});
} }
} }
var firmware = new Firmware(); var firmware = new Firmware();