Adding Invert commands to groups

This commit is contained in:
Robert Strouse 2024-01-05 17:03:45 -08:00
parent 4272d2245e
commit 9d3d7ae21f
9 changed files with 56 additions and 14 deletions

View file

@ -7,10 +7,10 @@
extern Preferences pref; extern Preferences pref;
#define SHADE_HDR_VER 17 #define SHADE_HDR_VER 18
#define SHADE_HDR_SIZE 56 #define SHADE_HDR_SIZE 56
#define SHADE_REC_SIZE 272 #define SHADE_REC_SIZE 272
#define GROUP_REC_SIZE 184 #define GROUP_REC_SIZE 190
#define TRANS_REC_SIZE 74 #define TRANS_REC_SIZE 74
extern ConfigSettings settings; extern ConfigSettings settings;
@ -597,6 +597,7 @@ bool ShadeConfigFile::readGroupRecord(SomfyGroup *group) {
if(group->getGroupId() == 255) group->clear(); if(group->getGroupId() == 255) group->clear();
else group->compressLinkedShadeIds(); else group->compressLinkedShadeIds();
if(this->header.version >= 18) group->flipCommands = this->readBool(false);
pref.end(); pref.end();
if(this->file.position() != startPos + this->header.groupRecordSize) { if(this->file.position() != startPos + this->header.groupRecordSize) {
Serial.println("Reading to end of group record"); Serial.println("Reading to end of group record");
@ -738,7 +739,8 @@ bool ShadeConfigFile::writeGroupRecord(SomfyGroup *group) {
this->writeUInt8(group->linkedShades[j]); this->writeUInt8(group->linkedShades[j]);
} }
this->writeUInt8(group->repeats); this->writeUInt8(group->repeats);
this->writeUInt8(group->sortOrder, CFG_REC_END); this->writeUInt8(group->sortOrder);
this->writeBool(group->flipCommands, CFG_REC_END);
return true; return true;
} }
bool ShadeConfigFile::writeShadeRecord(SomfyShade *shade) { bool ShadeConfigFile::writeShadeRecord(SomfyShade *shade) {

View file

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

View file

@ -375,6 +375,7 @@ bool GitUpdater::beginUpdate(const char *version) {
this->error = this->downloadFile(); this->error = this->downloadFile();
if(this->error == 0) { if(this->error == 0) {
settings.fwVersion.parse(version); settings.fwVersion.parse(version);
delay(100);
Serial.println("Committing Configuration..."); Serial.println("Committing Configuration...");
somfy.commit(); somfy.commit();
rebootDelay.reboot = true; rebootDelay.reboot = true;
@ -415,6 +416,7 @@ int8_t GitUpdater::downloadFile() {
uint8_t *buff = (uint8_t *)malloc(MAX_BUFF_SIZE); uint8_t *buff = (uint8_t *)malloc(MAX_BUFF_SIZE);
if(buff) { if(buff) {
this->emitDownloadProgress(len, total); this->emitDownloadProgress(len, total);
int timeouts = 0;
while(https.connected() && (len > 0 || len == -1) && total < len) { while(https.connected() && (len > 0 || len == -1) && total < len) {
size_t size = stream->available(); size_t size = stream->available();
if(size) { if(size) {
@ -453,6 +455,19 @@ int8_t GitUpdater::downloadFile() {
https.end(); https.end();
} }
} }
else {
timeouts++;
if(timeouts >= 300) {
Update.abort();
https.end();
free(buff);
Serial.println("Stream timeout!!!");
return -43;
}
sockEmit.loop();
webServer.loop();
delay(100);
}
} }
free(buff); free(buff);
if(len > total) { if(len > total) {

View file

@ -1469,6 +1469,7 @@ void SomfyGroup::publishState() {
if(mqtt.connected()) { if(mqtt.connected()) {
this->publish("direction", this->direction, true); this->publish("direction", this->direction, true);
this->publish("lastRollingCode", this->lastRollingCode, true); this->publish("lastRollingCode", this->lastRollingCode, true);
this->publish("flipCommands", this->flipCommands, true);
const uint8_t sunFlag = !!(this->flags & static_cast<uint8_t>(somfy_flags_t::SunFlag)); const uint8_t sunFlag = !!(this->flags & static_cast<uint8_t>(somfy_flags_t::SunFlag));
const uint8_t isSunny = !!(this->flags & static_cast<uint8_t>(somfy_flags_t::Sunny)); const uint8_t isSunny = !!(this->flags & static_cast<uint8_t>(somfy_flags_t::Sunny));
const uint8_t isWindy = !!(this->flags & static_cast<uint8_t>(somfy_flags_t::Windy)); const uint8_t isWindy = !!(this->flags & static_cast<uint8_t>(somfy_flags_t::Windy));
@ -1524,6 +1525,7 @@ void SomfyGroup::unpublish(uint8_t id) {
SomfyGroup::unpublish(id, "lastRollingCode"); SomfyGroup::unpublish(id, "lastRollingCode");
SomfyGroup::unpublish(id, "flags"); SomfyGroup::unpublish(id, "flags");
SomfyGroup::unpublish(id, "SunSensor"); SomfyGroup::unpublish(id, "SunSensor");
SomfyGroup::unpublish(id, "flipCommands");
} }
} }
void SomfyGroup::unpublish(uint8_t id, const char *topic) { void SomfyGroup::unpublish(uint8_t id, const char *topic) {
@ -3002,6 +3004,8 @@ bool SomfyGroup::fromJSON(JsonObject &obj) {
if(obj.containsKey("remoteAddress")) this->setRemoteAddress(obj["remoteAddress"]); if(obj.containsKey("remoteAddress")) this->setRemoteAddress(obj["remoteAddress"]);
if(obj.containsKey("bitLength")) this->bitLength = obj["bitLength"]; if(obj.containsKey("bitLength")) this->bitLength = obj["bitLength"];
if(obj.containsKey("proto")) this->proto = static_cast<radio_proto>(obj["proto"].as<uint8_t>()); if(obj.containsKey("proto")) this->proto = static_cast<radio_proto>(obj["proto"].as<uint8_t>());
if(obj.containsKey("flipCommands")) this->flipCommands = obj["flipCommands"].as<bool>();
//if(obj.containsKey("sunSensor")) this->hasSunSensor() = obj["sunSensor"]; This is calculated //if(obj.containsKey("sunSensor")) this->hasSunSensor() = obj["sunSensor"]; This is calculated
if(obj.containsKey("repeats")) this->repeats = obj["repeats"]; if(obj.containsKey("repeats")) this->repeats = obj["repeats"];
if(obj.containsKey("linkedShades")) { if(obj.containsKey("linkedShades")) {
@ -3024,6 +3028,7 @@ bool SomfyGroup::toJSON(JsonObject &obj) {
obj["bitLength"] = this->bitLength; obj["bitLength"] = this->bitLength;
obj["proto"] = static_cast<uint8_t>(this->proto); obj["proto"] = static_cast<uint8_t>(this->proto);
obj["sunSensor"] = this->hasSunSensor(); obj["sunSensor"] = this->hasSunSensor();
obj["flipCommands"] = this->flipCommands;
obj["flags"] = this->flags; obj["flags"] = this->flags;
obj["repeats"] = this->repeats; obj["repeats"] = this->repeats;
obj["sortOrder"] = this->sortOrder; obj["sortOrder"] = this->sortOrder;

Binary file not shown.

Binary file not shown.

View file

@ -1 +1 @@
2.3.0 2.3.1

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.3.0" type="text/css" /> <link rel="stylesheet" href="main.css?v=2.3.1" type="text/css" />
<link rel="stylesheet" href="widgets.css?v=2.3.0" type="text/css" /> <link rel="stylesheet" href="widgets.css?v=2.3.1" type="text/css" />
<link rel="stylesheet" href="icons.css?v=2.3.0" type="text/css" /> <link rel="stylesheet" href="icons.css?v=2.3.1" 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.3.0"></script> <script type="text/javascript" src="index.js?v=2.3.1"></script>
</head> </head>
<body> <body>
<div id="divContainer" class="container main" data-auth="false"> <div id="divContainer" class="container main" data-auth="false">
@ -554,6 +554,13 @@
<input id="fldGroupName" name="groupName" data-bind="name" type="text" length=20 placeholder="Name"> <input id="fldGroupName" name="groupName" data-bind="name" type="text" length=20 placeholder="Name">
<label for="fldGroupName">Name</label> <label for="fldGroupName">Name</label>
</div> </div>
<div style="margin-top:-10px;" id="divFlipGrpCommands">
<div class="field-group" style="display:inline-block">
<input id="cbFlipGrpCommands" name="flipCommands" data-bind="flipCommands" type="checkbox" style="" />
<label for="cbFlipGrpCommands" style="display:block;font-size:1em;margin-top:0px;margin-left:7px;display:inline-block;">Invert Commands</label>
</div>
</div>
<div classs="field-group" style="display:inline-block;"> <div classs="field-group" style="display:inline-block;">
<label for="selRepeatCommnds" style="cursor:pointer;color:#00bcd4;margin-right:4px;">Repeat Commands</label> <label for="selRepeatCommnds" style="cursor:pointer;color:#00bcd4;margin-right:4px;">Repeat Commands</label>
<select id="selRepeatCommands" data-bind="repeats" data-datatype="int" style="width:127px;"> <select id="selRepeatCommands" data-bind="repeats" data-datatype="int" style="width:127px;">

View file

@ -19,7 +19,8 @@ var errors = [
{ code: -32, desc: "Git Update: Aborted." }, { code: -32, desc: "Git Update: Aborted." },
{ code: -40, desc: "Git Download: Http Error." }, { code: -40, desc: "Git Download: Http Error." },
{ code: -41, desc: "Git Download: Buffer Allocation Error." }, { code: -41, desc: "Git Download: Buffer Allocation Error." },
{ code: -42, desc: "Git Download: Download Connection Error." } { code: -42, desc: "Git Download: Download Connection Error." },
{ code: -43, desc: 'Git Download: Timeout Error.' }
] ]
document.oncontextmenu = (event) => { document.oncontextmenu = (event) => {
if (event.target && event.target.tagName.toLowerCase() === 'input' && (event.target.type.toLowerCase() === 'text' || event.target.type.toLowerCase() === 'password')) if (event.target && event.target.tagName.toLowerCase() === 'input' && (event.target.type.toLowerCase() === 'text' || event.target.type.toLowerCase() === 'password'))
@ -1255,7 +1256,7 @@ var security = new Security();
class General { class General {
initialized = false; initialized = false;
appVersion = 'v2.3.0'; appVersion = 'v2.3.1';
reloadApp = false; reloadApp = false;
init() { init() {
if (this.initialized) return; if (this.initialized) return;
@ -2830,9 +2831,9 @@ class Somfy {
document.getElementById('spanShadeId').innerText = '*'; document.getElementById('spanShadeId').innerText = '*';
document.getElementById('divLinkedRemoteList').innerHTML = ''; document.getElementById('divLinkedRemoteList').innerHTML = '';
document.getElementById('btnSetRollingCode').style.display = 'none'; document.getElementById('btnSetRollingCode').style.display = 'none';
document.getElementById('selShadeBitLength').value = 56; //document.getElementById('selShadeBitLength').value = 56;
document.getElementById('cbFlipCommands').value = false; //document.getElementById('cbFlipCommands').value = false;
document.getElementById('cbFlipPosition').value = false; //document.getElementById('cbFlipPosition').value = false;
if (err) { if (err) {
ui.serviceError(err); ui.serviceError(err);
} }
@ -2842,6 +2843,7 @@ class Somfy {
shade.name = ''; shade.name = '';
shade.downTime = shade.upTime = 10000; shade.downTime = shade.upTime = 10000;
shade.tiltTime = 7000; shade.tiltTime = 7000;
shade.bitLength = 56;
shade.flipCommands = shade.flipPosition = false; shade.flipCommands = shade.flipPosition = false;
ui.toElement(elShade, shade); ui.toElement(elShade, shade);
this.showEditShade(true); this.showEditShade(true);
@ -2910,6 +2912,7 @@ class Somfy {
else { else {
console.log(group); console.log(group);
group.name = ''; group.name = '';
group.flipCommands = false;
ui.toElement(document.getElementById('somfyGroup'), group); ui.toElement(document.getElementById('somfyGroup'), group);
this.showEditGroup(true); this.showEditGroup(true);
} }
@ -3977,6 +3980,16 @@ class Firmware {
break; break;
case 3: // Updating -- this will be set by the update progress. case 3: // Updating -- this will be set by the update progress.
break; break;
case 4:
div.style.color = 'red';
let e = errors.find(x => x.code === rel.error) || { code: err.code, desc: 'Unspecified error' };
let inst = document.getElementById('divGitInstall');
if (inst) {
inst.remove();
ui.errorMessage(e.desc);
}
div.innerHTML = e.desc;
break;
case 5: case 5:
div.style.color = 'red'; div.style.color = 'red';
div.innerHTML = `Cancelling firmware update`; div.innerHTML = `Cancelling firmware update`;