Gate Control #199 Prog Hold for Groups #195

This commit is contained in:
Robert Strouse 2023-12-10 11:19:51 -08:00
parent d97f150439
commit 0c36c8e746
9 changed files with 398 additions and 257 deletions

View file

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

View file

@ -820,6 +820,17 @@ void SomfyShade::setGPIOs() {
digitalWrite(this->gpioDown, this->currentPos == 100 ? HIGH : LOW); digitalWrite(this->gpioDown, this->currentPos == 100 ? HIGH : LOW);
this->gpioDir = this->currentPos == 100 ? 1 : -1; this->gpioDir = this->currentPos == 100 ? 1 : -1;
} }
else if(this->shadeType == shade_types::drycontact2) {
if(this->currentPos == 100) {
digitalWrite(this->gpioDown, LOW);
digitalWrite(this->gpioUp, HIGH);
}
else {
digitalWrite(this->gpioUp, LOW);
digitalWrite(this->gpioDown, HIGH);
}
this->gpioDir = this->currentPos == 100 ? 1 : -1;
}
else { else {
switch(dir) { switch(dir) {
case -1: case -1:
@ -867,7 +878,7 @@ void SomfyShade::triggerGPIOs(somfy_frame_t &frame) {
} }
break; break;
case somfy_commands::Up: case somfy_commands::Up:
if(this->shadeType != shade_types::drycontact && this->shadeType != shade_types::garage1) { if(this->shadeType != shade_types::drycontact && this->shadeType != shade_types::garage1 && this->shadeType != shade_types::drycontact2) {
digitalWrite(this->gpioMy, LOW); digitalWrite(this->gpioMy, LOW);
digitalWrite(this->gpioDown, LOW); digitalWrite(this->gpioDown, LOW);
digitalWrite(this->gpioUp, HIGH); digitalWrite(this->gpioUp, HIGH);
@ -877,7 +888,7 @@ void SomfyShade::triggerGPIOs(somfy_frame_t &frame) {
break; break;
case somfy_commands::Toggle: case somfy_commands::Toggle:
case somfy_commands::Down: case somfy_commands::Down:
if(this->shadeType != shade_types::drycontact && this->shadeType != shade_types::garage1) { if(this->shadeType != shade_types::drycontact && this->shadeType != shade_types::garage1 && this->shadeType != shade_types::drycontact2) {
digitalWrite(this->gpioMy, LOW); digitalWrite(this->gpioMy, LOW);
digitalWrite(this->gpioUp, LOW); digitalWrite(this->gpioUp, LOW);
} }
@ -886,7 +897,7 @@ void SomfyShade::triggerGPIOs(somfy_frame_t &frame) {
Serial.printf("UP: false, DOWN: true, MY: false\n"); Serial.printf("UP: false, DOWN: true, MY: false\n");
break; break;
case somfy_commands::MyUp: case somfy_commands::MyUp:
if(this->shadeType != shade_types::drycontact && this->shadeType != shade_types::garage1) { if(this->shadeType != shade_types::drycontact && this->shadeType != shade_types::garage1 && this->shadeType != shade_types::drycontact2) {
digitalWrite(this->gpioDown, LOW); digitalWrite(this->gpioDown, LOW);
digitalWrite(this->gpioMy, HIGH); digitalWrite(this->gpioMy, HIGH);
digitalWrite(this->gpioUp, HIGH); digitalWrite(this->gpioUp, HIGH);
@ -894,7 +905,7 @@ void SomfyShade::triggerGPIOs(somfy_frame_t &frame) {
} }
break; break;
case somfy_commands::MyDown: case somfy_commands::MyDown:
if(this->shadeType != shade_types::drycontact && this->shadeType != shade_types::garage1) { if(this->shadeType != shade_types::drycontact && this->shadeType != shade_types::garage1 && this->shadeType != shade_types::drycontact2) {
digitalWrite(this->gpioUp, LOW); digitalWrite(this->gpioUp, LOW);
digitalWrite(this->gpioMy, HIGH); digitalWrite(this->gpioMy, HIGH);
digitalWrite(this->gpioDown, HIGH); digitalWrite(this->gpioDown, HIGH);
@ -902,7 +913,7 @@ void SomfyShade::triggerGPIOs(somfy_frame_t &frame) {
} }
break; break;
case somfy_commands::MyUpDown: case somfy_commands::MyUpDown:
if(this->shadeType != shade_types::drycontact && this->shadeType != shade_types::garage1) { if(this->shadeType != shade_types::drycontact && this->shadeType != shade_types::garage1 && this->shadeType != shade_types::drycontact2) {
digitalWrite(this->gpioUp, HIGH); digitalWrite(this->gpioUp, HIGH);
digitalWrite(this->gpioMy, HIGH); digitalWrite(this->gpioMy, HIGH);
digitalWrite(this->gpioDown, HIGH); digitalWrite(this->gpioDown, HIGH);
@ -924,7 +935,7 @@ void SomfyShade::checkMovement() {
int32_t downTime = (int32_t)this->downTime; int32_t downTime = (int32_t)this->downTime;
int32_t upTime = (int32_t)this->upTime; int32_t upTime = (int32_t)this->upTime;
int32_t tiltTime = (int32_t)this->tiltTime; int32_t tiltTime = (int32_t)this->tiltTime;
if(this->shadeType == shade_types::drycontact) downTime = upTime = tiltTime = 1; if(this->shadeType == shade_types::drycontact || this->shadeType == shade_types::drycontact2) downTime = upTime = tiltTime = 1;
// We are checking movement for essentially 3 types of motors. // We are checking movement for essentially 3 types of motors.
@ -1334,6 +1345,9 @@ void SomfyShade::publishDisco() {
obj["state_closing"] = this->flipPosition ? "-1" : "1"; obj["state_closing"] = this->flipPosition ? "-1" : "1";
obj["state_opening"] = this->flipPosition ? "1" : "-1"; obj["state_opening"] = this->flipPosition ? "1" : "-1";
break; break;
case shade_types::lgate:
case shade_types::cgate:
case shade_types::rgate:
case shade_types::ldrapery: case shade_types::ldrapery:
case shade_types::rdrapery: case shade_types::rdrapery:
case shade_types::cdrapery: case shade_types::cdrapery:
@ -1373,6 +1387,7 @@ void SomfyShade::publishDisco() {
obj["state_closing"] = this->flipPosition ? "-1" : "1"; obj["state_closing"] = this->flipPosition ? "-1" : "1";
obj["state_opening"] = this->flipPosition ? "1" : "-1"; obj["state_opening"] = this->flipPosition ? "1" : "-1";
break; break;
case shade_types::drycontact2:
case shade_types::drycontact: case shade_types::drycontact:
break; break;
default: default:
@ -1385,7 +1400,7 @@ void SomfyShade::publishDisco() {
obj["state_opening"] = this->flipPosition ? "1" : "-1"; obj["state_opening"] = this->flipPosition ? "1" : "-1";
break; break;
} }
if(this->shadeType != shade_types::drycontact) { if(this->shadeType != shade_types::drycontact && this->shadeType != shade_types::drycontact2) {
if(this->tiltType != tilt_types::tiltonly) { if(this->tiltType != tilt_types::tiltonly) {
obj["command_topic"] = "~/direction/set"; obj["command_topic"] = "~/direction/set";
obj["position_topic"] = "~/position"; obj["position_topic"] = "~/position";
@ -1881,7 +1896,7 @@ void SomfyShade::processFrame(somfy_frame_t &frame, bool internal) {
switch(cmd) { switch(cmd) {
case somfy_commands::Sensor: case somfy_commands::Sensor:
this->lastFrame.processed = true; this->lastFrame.processed = true;
if(this->shadeType == shade_types::drycontact) return; if(this->shadeType == shade_types::drycontact || this->shadeType == shade_types::drycontact2) return;
{ {
const uint8_t prevFlags = this->flags; const uint8_t prevFlags = this->flags;
const bool wasSunny = prevFlags & static_cast<uint8_t>(somfy_flags_t::Sunny); const bool wasSunny = prevFlags & static_cast<uint8_t>(somfy_flags_t::Sunny);
@ -1960,13 +1975,13 @@ void SomfyShade::processFrame(somfy_frame_t &frame, bool internal) {
case somfy_commands::MyUpDown: case somfy_commands::MyUpDown:
case somfy_commands::UpDown: case somfy_commands::UpDown:
this->lastFrame.processed = true; this->lastFrame.processed = true;
if(this->shadeType == shade_types::drycontact) return; if(this->shadeType == shade_types::drycontact || this->shadeType == shade_types::drycontact2) return;
this->emitCommand(cmd, internal ? "internal" : "remote", frame.remoteAddress); this->emitCommand(cmd, internal ? "internal" : "remote", frame.remoteAddress);
break; break;
case somfy_commands::Flag: case somfy_commands::Flag:
this->lastFrame.processed = true; this->lastFrame.processed = true;
if(this->shadeType == shade_types::drycontact) return; if(this->shadeType == shade_types::drycontact || this->shadeType == shade_types::drycontact2) return;
if(this->lastFrame.rollingCode & 0x8000) return; // Some sensors send bogus frames with a rollingCode >= 32768 that cause them to change the state. if(this->lastFrame.rollingCode & 0x8000) return; // Some sensors send bogus frames with a rollingCode >= 32768 that cause them to change the state.
this->p_sunFlag(false); this->p_sunFlag(false);
//this->flags &= ~(static_cast<uint8_t>(somfy_flags_t::SunFlag)); //this->flags &= ~(static_cast<uint8_t>(somfy_flags_t::SunFlag));
@ -1976,7 +1991,7 @@ void SomfyShade::processFrame(somfy_frame_t &frame, bool internal) {
somfy.updateGroupFlags(); somfy.updateGroupFlags();
break; break;
case somfy_commands::SunFlag: case somfy_commands::SunFlag:
if(this->shadeType == shade_types::drycontact) return; if(this->shadeType == shade_types::drycontact || this->shadeType == shade_types::drycontact2) return;
if(this->lastFrame.rollingCode & 0x8000) return; // Some sensors send bogus frames with a rollingCode >= 32768 that cause them to change the state. if(this->lastFrame.rollingCode & 0x8000) return; // Some sensors send bogus frames with a rollingCode >= 32768 that cause them to change the state.
{ {
const bool isWindy = this->flags & static_cast<uint8_t>(somfy_flags_t::Windy); const bool isWindy = this->flags & static_cast<uint8_t>(somfy_flags_t::Windy);
@ -2009,6 +2024,13 @@ void SomfyShade::processFrame(somfy_frame_t &frame, bool internal) {
this->lastFrame.processed = true; this->lastFrame.processed = true;
return; return;
} }
else if(this->shadeType == shade_types::drycontact2) {
if(this->lastFrame.processed) return;
this->lastFrame.processed = true;
if(this->currentPos != 0.0f) this->p_target(0);
this->emitCommand(cmd, internal ? "internal" : "remote", frame.remoteAddress);
return;
}
if(this->tiltType == tilt_types::tiltmotor || this->tiltType == tilt_types::euromode) { if(this->tiltType == tilt_types::tiltmotor || this->tiltType == tilt_types::euromode) {
// Wait another half second just in case we are potentially processing a tilt. // Wait another half second just in case we are potentially processing a tilt.
if(!internal) this->lastFrame.await = curTime + 500; if(!internal) this->lastFrame.await = curTime + 500;
@ -2030,6 +2052,13 @@ void SomfyShade::processFrame(somfy_frame_t &frame, bool internal) {
this->lastFrame.processed = true; this->lastFrame.processed = true;
return; return;
} }
else if(this->shadeType == shade_types::drycontact2) {
if(this->lastFrame.processed) return;
this->lastFrame.processed = true;
if(this->currentPos != 100.0f) this->p_target(100);
this->emitCommand(cmd, internal ? "internal" : "remote", frame.remoteAddress);
return;
}
if (!this->windLast || (curTime - this->windLast) >= SOMFY_NO_WIND_REMOTE_TIMEOUT) { if (!this->windLast || (curTime - this->windLast) >= SOMFY_NO_WIND_REMOTE_TIMEOUT) {
if(this->tiltType == tilt_types::tiltmotor || this->tiltType == tilt_types::euromode) { if(this->tiltType == tilt_types::tiltmotor || this->tiltType == tilt_types::euromode) {
// Wait another half seccond just in case we are potentially processing a tilt. // Wait another half seccond just in case we are potentially processing a tilt.
@ -2047,6 +2076,7 @@ void SomfyShade::processFrame(somfy_frame_t &frame, bool internal) {
} }
break; break;
case somfy_commands::My: case somfy_commands::My:
if(this->shadeType == shade_types::drycontact2) return;
if(this->shadeType == shade_types::garage1) { if(this->shadeType == shade_types::garage1) {
if(this->lastFrame.processed) return; if(this->lastFrame.processed) return;
this->lastFrame.processed = true; this->lastFrame.processed = true;
@ -2093,7 +2123,7 @@ void SomfyShade::processFrame(somfy_frame_t &frame, bool internal) {
case somfy_commands::StepUp: case somfy_commands::StepUp:
if(this->lastFrame.processed) return; if(this->lastFrame.processed) return;
this->lastFrame.processed = true; this->lastFrame.processed = true;
if(this->shadeType == shade_types::drycontact) return; if(this->shadeType == shade_types::drycontact || this->shadeType == shade_types::drycontact2) return;
dir = 0; dir = 0;
// With the step commands and integrated shades // With the step commands and integrated shades
// the motor must tilt in the direction first then move // the motor must tilt in the direction first then move
@ -2115,7 +2145,7 @@ void SomfyShade::processFrame(somfy_frame_t &frame, bool internal) {
case somfy_commands::StepDown: case somfy_commands::StepDown:
if(this->lastFrame.processed) return; if(this->lastFrame.processed) return;
this->lastFrame.processed = true; this->lastFrame.processed = true;
if(this->shadeType == shade_types::drycontact) return; if(this->shadeType == shade_types::drycontact || this->shadeType == shade_types::drycontact2) return;
dir = 1; dir = 1;
// With the step commands and integrated shades // With the step commands and integrated shades
// the motor must tilt in the direction first then move // the motor must tilt in the direction first then move
@ -2474,6 +2504,7 @@ void SomfyShade::sendCommand(somfy_commands cmd, uint8_t repeat) {
else if(cmd == somfy_commands::My) { else if(cmd == somfy_commands::My) {
if(this->shadeType == shade_types::garage1 || this->shadeType == shade_types::drycontact) if(this->shadeType == shade_types::garage1 || this->shadeType == shade_types::drycontact)
SomfyRemote::sendCommand(cmd, repeat); SomfyRemote::sendCommand(cmd, repeat);
else if(this->shadeType == shade_types::drycontact2) return;
else if(this->isIdle()) { else if(this->isIdle()) {
this->moveToMyPosition(); this->moveToMyPosition();
return; return;
@ -2653,6 +2684,8 @@ bool SomfyShade::usesPin(uint8_t pin) {
else if(this->shadeType == shade_types::garage1) { else if(this->shadeType == shade_types::garage1) {
if(this->proto == radio_proto::GP_Relay && this->gpioUp == pin) return true; if(this->proto == radio_proto::GP_Relay && this->gpioUp == pin) return true;
} }
else if(this->shadeType == shade_types::drycontact2)
if(this->proto == radio_proto::GP_Relay && (this->gpioUp == pin || this->gpioDown == pin)) return true;
else { else {
if(this->gpioUp == pin) return true; if(this->gpioUp == pin) return true;
else if(this->proto == radio_proto::GP_Remote && this->gpioMy == pin) return true; else if(this->proto == radio_proto::GP_Remote && this->gpioMy == pin) return true;
@ -2682,6 +2715,8 @@ int8_t SomfyShade::validateJSON(JsonObject &obj) {
type = shade_types::awning; type = shade_types::awning;
else if(strncmp(obj["shadeType"].as<const char *>(), "shutter", 8) == 0) else if(strncmp(obj["shadeType"].as<const char *>(), "shutter", 8) == 0)
type = shade_types::shutter; type = shade_types::shutter;
else if(strncmp(obj["shadeType"].as<const char *>(), "drycontact2", 12) == 0)
type = shade_types::drycontact2;
else if(strncmp(obj["shadeType"].as<const char *>(), "drycontact", 11) == 0) else if(strncmp(obj["shadeType"].as<const char *>(), "drycontact", 11) == 0)
type = shade_types::drycontact; type = shade_types::drycontact;
} }
@ -2698,6 +2733,7 @@ int8_t SomfyShade::validateJSON(JsonObject &obj) {
uint8_t downPin = obj.containsKey("gpioDown") ? obj["gpioDown"].as<uint8_t>() : this->gpioDown; uint8_t downPin = obj.containsKey("gpioDown") ? obj["gpioDown"].as<uint8_t>() : this->gpioDown;
uint8_t myPin = obj.containsKey("gpioMy") ? obj["gpioMy"].as<uint8_t>() : this->gpioMy; uint8_t myPin = obj.containsKey("gpioMy") ? obj["gpioMy"].as<uint8_t>() : this->gpioMy;
if(type == shade_types::drycontact || (type == shade_types::garage1 && proto == radio_proto::GP_Remote)) upPin = myPin = 255; if(type == shade_types::drycontact || (type == shade_types::garage1 && proto == radio_proto::GP_Remote)) upPin = myPin = 255;
else if(type == shade_types::drycontact2) myPin = 255;
if(proto == radio_proto::GP_Relay) myPin = 255; if(proto == radio_proto::GP_Relay) myPin = 255;
if(somfy.transceiver.config.enabled) { if(somfy.transceiver.config.enabled) {
if((upPin != 255 && somfy.transceiver.usesPin(upPin)) || if((upPin != 255 && somfy.transceiver.usesPin(upPin)) ||
@ -2761,6 +2797,8 @@ int8_t SomfyShade::fromJSON(JsonObject &obj) {
this->shadeType = shade_types::awning; this->shadeType = shade_types::awning;
else if(strncmp(obj["shadeType"].as<const char *>(), "shutter", 8) == 0) else if(strncmp(obj["shadeType"].as<const char *>(), "shutter", 8) == 0)
this->shadeType = shade_types::shutter; this->shadeType = shade_types::shutter;
else if(strncmp(obj["shadeType"].as<const char *>(), "drycontact2", 12) == 0)
this->shadeType = shade_types::drycontact2;
else if(strncmp(obj["shadeType"].as<const char *>(), "drycontact", 11) == 0) else if(strncmp(obj["shadeType"].as<const char *>(), "drycontact", 11) == 0)
this->shadeType = shade_types::drycontact; this->shadeType = shade_types::drycontact;
} }

View file

@ -59,6 +59,10 @@ enum class shade_types : byte {
rdrapery = 0x07, rdrapery = 0x07,
cdrapery = 0x08, cdrapery = 0x08,
drycontact = 0x09, drycontact = 0x09,
drycontact2 = 0x0A,
lgate = 0x0B,
cgate = 0x0C,
rgate = 0x0D
}; };
enum class tilt_types : byte { enum class tilt_types : byte {
none = 0x00, none = 0x00,

Binary file not shown.

Binary file not shown.

View file

@ -1248,3 +1248,227 @@ i.icss-github-o {
top: .2em; top: .2em;
transform: rotate(65deg); transform: rotate(65deg);
} }
i.icss-lgate {
width: 1.1em;
height: .9em;
background-color: transparent;
border: .05em solid transparent;
border-width: 0 .1em;
margin: .1em 0 .07em;
}
i.icss-lgate:before {
width: 1.1em;
height: 1em;
border-bottom: solid 1px;
top: -.05em;
left: -.09em;
}
i.icss-lgate > span.icss-panel-right {
display:inline-block;
width: var(--shade-position, 0%);
height: calc(100% - .005em);
right: calc(100% - var(--shade-position, 0%));
left: 0em;
top: 0.025em;
border-bottom: solid 0.025em gray;
border-right: solid 0.025em gray;
background-image: repeating-linear-gradient(to left, rgba(255,255,255,0) 0% 75%, var(--shade-color, currentColor) 75% 100%, rgba(255,255,255,0) 75% 0%);
background-position: 0 0, 100% 100%;
background-size: .1em 1em;
background-color: rgba(71, 212, 255, 0);
transform: rotate(180deg);
}
i.icss-lgate > span.icss-panel-right:after {
position: absolute;
content:"";
display: inline-block;
border: solid 1px var(--shade-color, currentColor);
width: .02em;
height: .9em;
left: -.05em;
background: var(--shade-color, currentColor);
}
i.icss-lgate > span.icss-panel-left {
position: absolute;
display: inline-block;
}
i.icss-lgate > span.icss-panel-left:before {
position: absolute;
display: inline-block;
content:"";
left: -.15em;
top: -.1em;
height: 1em;
width: .1em;
border: solid 1px;
border-top-left-radius: .05em;
border-top-right-radius: .05em;
background-color: black;
}
i.icss-rgate {
width: 1.1em;
height: .9em;
background-color: transparent;
border: .05em solid transparent;
border-width: 0 .1em;
margin: .1em 0 .07em;
}
i.icss-rgate:before {
width: 1.1em;
height: 1em;
border-bottom: solid 1px;
top: -.05em;
left: -.09em;
}
i.icss-rgate > span.icss-panel-left {
position: absolute;
display: inline-block;
width: var(--shade-position, 0%);
height: calc(100% - .005em);
left: calc(100% - var(--shade-position, 0%));
top: 0.025em;
border-top: solid 0.025em gray;
border-right: solid 0.025em gray;
background-image: repeating-linear-gradient(to left, rgba(255,255,255,0) 0% 75%, var(--shade-color, currentColor) 75% 100%, rgba(255,255,255,0) 75% 0%);
background-position: 0 0, 100% 100%;
background-size: .1em 1em;
background-color: rgba(71, 212, 255, 0);
margin-left:-.025em;
}
i.icss-rgate > span.icss-panel-left:after {
position: absolute;
content: "";
display: inline-block;
border: solid 1px var(--shade-color, currentColor);
top:-0.07em;
width: .02em;
height: .9em;
left: -.05em;
background: var(--shade-color, currentColor);
}
i.icss-rgate > span.icss-panel-right {
position: absolute;
display: inline-block;
left:calc(100% - .05em);
}
i.icss-rgate > span.icss-panel-right:before {
position: absolute;
display: inline-block;
content: "";
right: -.15em;
top: -.1em;
height: 1em;
width: .1em;
border: solid 1px;
border-top-left-radius: .05em;
border-top-right-radius: .05em;
background-color: black;
}
i.icss-cgate {
width: 1.1em;
height: .9em;
background-color: transparent;
border: .05em solid transparent;
border-width: 0 .1em;
margin: .1em 0 .07em;
}
i.icss-cgate:before {
width: 1.1em;
height: 1em;
border-bottom: solid 1px;
top: -.05em;
left: -.09em;
}
i.icss-cgate > span.icss-panel-left {
position: absolute;
display: inline-block;
width: calc(var(--shade-position, 0%) / 2);
height: calc(100% - .005em);
left: 0%;
top: 0.025em;
border-bottom: solid 0.025em gray;
border-right: solid 0.025em gray;
background-image: repeating-linear-gradient(to left, rgba(255,255,255,0) 0% 75%, var(--shade-color, currentColor) 75% 100%, rgba(255,255,255,0) 75% 0%);
background-position: 0 0, 100% 100%;
background-size: .1em 1em;
background-color: rgba(71, 212, 255, 0);
margin-left: -.025em;
transform: rotate(180deg);
}
i.icss-cgate > span.icss-panel-left:after {
position: absolute;
content: "";
display: inline-block;
border: solid 1px var(--shade-color, currentColor);
top: 0em;
width: .02em;
height: .9em;
left: -.05em;
background: var(--shade-color, currentColor);
}
i.icss-cgate > span.icss-panel-left:before {
position: absolute;
display: inline-block;
content: "";
right: -.15em;
top: -.025em;
height: 1em;
width: .1em;
border: solid 1px;
border-bottom-left-radius: .05em;
border-bottom-right-radius: .05em;
background-color: black;
}
i.icss-cgate > span.icss-panel-right {
position: absolute;
display: inline-block;
width: calc(var(--shade-position, 0%) / 2);
height: calc(100% - .005em);
left: calc(100% - calc(var(--shade-position, 0%) / 2));
top: .025em;
border-top: solid 0.025em gray;
border-right: solid 0.025em gray;
background-image: repeating-linear-gradient(to left, rgba(255,255,255,0) 0% 75%, var(--shade-color, currentColor) 75% 100%, rgba(255,255,255,0) 75% 0%);
background-position: 0 0, 100% 100%;
background-size: .1em 1em;
background-color: rgba(71, 212, 255, 0);
margin-left: -.025em;
}
i.icss-cgate > span.icss-panel-right:after {
position: absolute;
content: "";
display: inline-block;
border: solid 1px var(--shade-color, currentColor);
top: -.072em;
width: .02em;
height: .9em;
left: -.05em;
background: var(--shade-color, currentColor);
}
i.icss-cgate > span.icss-panel-right:before {
position: absolute;
display: inline-block;
content: "";
right: -.15em;
top: -.15em;
height: 1em;
width: .1em;
border: solid 1px;
border-top-left-radius: .05em;
border-top-right-radius: .05em;
background-color: black;
}

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.2.2b" type="text/css" /> <link rel="stylesheet" href="main.css?v=2.2.2c" type="text/css" />
<link rel="stylesheet" href="widgets.css?v=2.2.2b" type="text/css" /> <link rel="stylesheet" href="widgets.css?v=2.2.2c" type="text/css" />
<link rel="stylesheet" href="icons.css?v=2.2.2b" type="text/css" /> <link rel="stylesheet" href="icons.css?v=2.2.2c" 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.2.2b"></script> <script type="text/javascript" src="index.js?v=2.2.2c"></script>
</head> </head>
<body> <body>
<div id="divContainer" class="container main" data-auth="false"> <div id="divContainer" class="container main" data-auth="false">
@ -353,6 +353,10 @@
<option value="5">Garage (1-button)</option> <option value="5">Garage (1-button)</option>
<option value="6">Garage (3-button)</option> <option value="6">Garage (3-button)</option>
<option value="9">Dry Contact</option> <option value="9">Dry Contact</option>
<option value="10">Dry Contact (2-button)</option>
<option value="11">Gate (left)</option>
<option value="12">Gate (center)</option>
<option value="13">Gate (right)</option>
</select> </select>
<label for="selShadeType">Type</label> <label for="selShadeType">Type</label>
</div> </div>

View file

@ -169,7 +169,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' : ''; var baseUrl = window.location.protocol === 'file:' ? 'http://192.168.1.152' : '';
//var baseUrl = ''; //var baseUrl = '';
function makeBool(val) { function makeBool(val) {
if (typeof val === 'boolean') return val; if (typeof val === 'boolean') return val;
@ -1252,7 +1252,7 @@ var security = new Security();
class General { class General {
initialized = false; initialized = false;
appVersion = 'v2.2.2b'; appVersion = 'v2.2.2c';
reloadApp = false; reloadApp = false;
init() { init() {
if (this.initialized) return; if (this.initialized) return;
@ -1885,6 +1885,22 @@ var wifi = new Wifi();
class Somfy { class Somfy {
initialized = false; initialized = false;
frames = []; frames = [];
shadeTypes = [
{ type: 0, name: 'Roller Shade', ico: 'icss-window-shade', lift: true, sun: true, fcmd: true, fpos: true },
{ type: 1, name: 'Blind', ico: 'icss-window-blind', lift: true, tilt: true, sun: true, fcmd: true, fpos: true },
{ type: 2, name: 'Drapery (left)', ico: 'icss-ldrapery', lift: true, sun: true, fcmd: true, fpos: true },
{ type: 3, name: 'Awning', ico: 'icss-awning', lift: true, sun: true, fcmd: true, fpos: true },
{ type: 4, name: 'Shutter', ico: 'icss-shutter', lift: true, sun: true, fcmd: true, fpos: true },
{ type: 5, name: 'Garage (1-button)', ico: 'icss-garage', lift: true, light: true, fpos: true },
{ type: 6, name: 'Garage (3-button)', ico: 'icss-garage', lift: true, light: true, fcmd: true, fpos: true },
{ type: 7, name: 'Drapery (right)', ico: 'icss-rdrapery', lift: true, sun: true, fcmd: true, fpos: true },
{ type: 8, name: 'Drapery (center)', ico: 'icss-cdrapery', lift: true, sun: true, fcmd: true, fpos: true },
{ type: 9, name: 'Dry Contact (1-button)', ico: 'icss-lightbulb', fpos: true },
{ type: 10, name: 'Dry Contact (2-button)', ico: 'icss-lightbulb', fcmd: true, fpos: true },
{ type: 11, name: 'Gate (left)', ico: 'icss-lgate', lift: true, fcmd: true, fpos: true },
{ type: 12, name: 'Gate (center)', ico: 'icss-cgate', lift: true, fcmd: true, fpos: true },
{ type: 13, name: 'Gate (right)', ico: 'icss-rgate', lift: true, fcmd: true, fpos: true },
];
init() { init() {
if (this.initialized) return; if (this.initialized) return;
this.loadPins('inout', document.getElementById('selTransSCKPin')); this.loadPins('inout', document.getElementById('selTransSCKPin'));
@ -2098,6 +2114,8 @@ class Somfy {
} }
for (let i = 0; i < shades.length; i++) { for (let i = 0; i < shades.length; i++) {
let shade = shades[i]; let shade = shades[i];
let st = this.shadeTypes.find(x => x.type === shade.shadeType) || { type: shade.shadeType, ico: 'icss-window-shade' };
divCfg += `<div class="somfyShade shade-draggable" draggable="true" data-mypos="${shade.myPos}" data-shadeid="${shade.shadeId}" data-remoteaddress="${shade.remoteAddress}" data-tilt="${shade.tiltType}" data-shadetype="${shade.shadeType}">`; divCfg += `<div class="somfyShade shade-draggable" draggable="true" data-mypos="${shade.myPos}" data-shadeid="${shade.shadeId}" data-remoteaddress="${shade.remoteAddress}" data-tilt="${shade.tiltType}" data-shadetype="${shade.shadeType}">`;
divCfg += `<div class="button-outline" onclick="somfy.openEditShade(${shade.shadeId});"><i class="icss-edit"></i></div>`; divCfg += `<div class="button-outline" onclick="somfy.openEditShade(${shade.shadeId});"><i class="icss-edit"></i></div>`;
//divCfg += `<i class="shade-icon" data-position="${shade.position || 0}%"></i>`; //divCfg += `<i class="shade-icon" data-position="${shade.position || 0}%"></i>`;
@ -2112,38 +2130,10 @@ class Somfy {
divCtl += ` data-tiltposition="${shade.tiltPosition}" data-tiltdirection="${shade.tiltDirection}" data-tilttarget="${shade.tiltTarget}"`; divCtl += ` data-tiltposition="${shade.tiltPosition}" data-tiltdirection="${shade.tiltDirection}" data-tilttarget="${shade.tiltTarget}"`;
} }
divCtl += `><div class="shade-icon" data-shadeid="${shade.shadeId}" onclick="event.stopPropagation(); console.log(event); somfy.openSetPosition(${shade.shadeId});">`; divCtl += `><div class="shade-icon" data-shadeid="${shade.shadeId}" onclick="event.stopPropagation(); console.log(event); somfy.openSetPosition(${shade.shadeId});">`;
divCtl += `<i class="somfy-shade-icon`; divCtl += `<i class="somfy-shade-icon ${st.ico}`;
switch (shade.shadeType) { //divCtl += `" data-shadeid="${shade.shadeId}" style="--shade-position:${shade.flipPosition ? 100 - shade.position : shade.position}%;vertical-align: top;"><span class="icss-panel-left"></span><span class="icss-panel-right"></span></i>`;
case 1: divCtl += `" data-shadeid="${shade.shadeId}" style="--shade-position:${shade.position}%;vertical-align: top;"><span class="icss-panel-left"></span><span class="icss-panel-right"></span></i>`;
divCtl += ' icss-window-blind';
break;
case 2:
divCtl += ' icss-ldrapery';
break;
case 3:
divCtl += ' icss-awning';
break;
case 4:
divCtl += ' icss-shutter';
break;
case 5:
case 6:
divCtl += ' icss-garage';
break;
case 7:
divCtl += ' icss-rdrapery';
break;
case 8:
divCtl += ' icss-cdrapery';
break;
case 9:
divCtl += ' icss-lightbulb';
break;
default:
divCtl += ' icss-window-shade';
break;
}
divCtl += `" data-shadeid="${shade.shadeId}" style="--shade-position:${shade.flipPosition ? 100 - shade.position : shade.position}%;vertical-align: top;"><span class="icss-panel-left"></span><span class="icss-panel-right"></span></i>`;
divCtl += shade.tiltType !== 0 ? `<i class="icss-window-tilt" data-shadeid="${shade.shadeId}" data-tiltposition="${shade.tiltPosition}"></i></div>` : '</div>'; divCtl += shade.tiltType !== 0 ? `<i class="icss-window-tilt" data-shadeid="${shade.shadeId}" data-tiltposition="${shade.tiltPosition}"></i></div>` : '</div>';
divCtl += `<div class="indicator indicator-wind"><i class="icss-warning"></i></div><div class="indicator indicator-sun"><i class="icss-sun"></i></div>`; divCtl += `<div class="indicator indicator-wind"><i class="icss-warning"></i></div><div class="indicator indicator-sun"><i class="icss-sun"></i></div>`;
divCtl += `<div class="shade-name">`; divCtl += `<div class="shade-name">`;
@ -2667,7 +2657,9 @@ class Somfy {
console.log(state); console.log(state);
let icons = document.querySelectorAll(`.somfy-shade-icon[data-shadeid="${state.shadeId}"]`); let icons = document.querySelectorAll(`.somfy-shade-icon[data-shadeid="${state.shadeId}"]`);
for (let i = 0; i < icons.length; i++) { for (let i = 0; i < icons.length; i++) {
icons[i].style.setProperty('--shade-position', `${state.flipPosition ? 100 - state.position : state.position}%`); //icons[i].style.setProperty('--shade-position', `${state.flipPosition ? 100 - state.position : state.position}%`);
icons[i].style.setProperty('--shade-position', `${state.position}%`);
} }
if (state.tiltType !== 0) { if (state.tiltType !== 0) {
let tilts = document.querySelectorAll(`.icss-window-tilt[data-shadeid="${state.shadeId}"]`); let tilts = document.querySelectorAll(`.icss-window-tilt[data-shadeid="${state.shadeId}"]`);
@ -2792,153 +2784,35 @@ class Somfy {
onShadeTypeChanged(el) { onShadeTypeChanged(el) {
let sel = document.getElementById('selShadeType'); let sel = document.getElementById('selShadeType');
let tilt = parseInt(document.getElementById('selTiltType').value, 10); let tilt = parseInt(document.getElementById('selTiltType').value, 10);
let sun = true;
let light = false;
let lift = true;
let flipCommands = true;
let flipPosition = true;
let ico = document.getElementById('icoShade'); let ico = document.getElementById('icoShade');
let type = parseInt(sel.value, 10); let type = parseInt(sel.value, 10);
document.getElementById('somfyShade').setAttribute('data-shadetype', type); document.getElementById('somfyShade').setAttribute('data-shadetype', type);
document.getElementById('divSomfyButtons').setAttribute('data-shadetype', type); document.getElementById('divSomfyButtons').setAttribute('data-shadetype', type);
switch (type) {
case 1: let st = this.shadeTypes.find(x => x.type === type) || { type: type };
document.getElementById('divTiltSettings').style.display = ''; for (let i = 0; i < this.shadeTypes.length; i++) {
if (ico.classList.contains('icss-window-shade')) ico.classList.remove('icss-window-shade'); let t = this.shadeTypes[i];
if (ico.classList.contains('icss-ldrapery')) ico.classList.remove('icss-ldrapery'); if (t.type !== type) {
if (ico.classList.contains('icss-rdrapery')) ico.classList.remove('icss-rdrapery'); if (ico.classList.contains(t.ico) && t.ico !== st.ico) ico.classList.remove(t.ico);
if (ico.classList.contains('icss-cdrapery')) ico.classList.remove('icss-cdrapery'); }
if (ico.classList.contains('icss-awning')) ico.classList.remove('icss-awning'); else {
if (ico.classList.contains('icss-shutter')) ico.classList.remove('icss-shutter'); if (!ico.classList.contains(st.ico)) ico.classList.add(st.ico);
if (!ico.classList.contains('icss-window-blind')) ico.classList.add('icss-window-blind'); document.getElementById('divTiltSettings').style.display = st.tilt !== false ? '' : 'none';
if (ico.classList.contains('icss-garage')) ico.classList.remove('icss-garage'); let lift = st.lift || false;
if (ico.classList.contains('icss-lightbulb')) ico.classList.remove('icss-lightbulb'); if (lift && tilt == 3) lift = false;
break; if (!st.tilt) tilt = 0;
case 2: document.getElementById('fldTiltTime').parentElement.style.display = tilt ? 'inline-block' : 'none';
document.getElementById('divTiltSettings').style.display = 'none'; document.getElementById('divLiftSettings').style.display = lift ? '' : 'none';
if (ico.classList.contains('icss-window-shade')) ico.classList.remove('icss-window-shade'); document.getElementById('divTiltSettings').style.display = st.tilt ? '' : 'none';
if (!ico.classList.contains('icss-ldrapery')) ico.classList.add('icss-ldrapery'); document.querySelector('#divSomfyButtons i.icss-window-tilt').style.display = tilt ? '' : 'none';
if (ico.classList.contains('icss-rdrapery')) ico.classList.remove('icss-rdrapery'); document.getElementById('divSunSensor').style.display = st.sun ? '' : 'none';
if (ico.classList.contains('icss-cdrapery')) ico.classList.remove('icss-cdrapery'); document.getElementById('divLightSwitch').style.display = st.light ? '' : 'none';
if (ico.classList.contains('icss-window-blind')) ico.classList.remove('icss-window-blind'); document.getElementById('divFlipPosition').style.display = st.fpos ? '' : 'none';
if (ico.classList.contains('icss-shutter')) ico.classList.remove('icss-shutter'); document.getElementById('divFlipCommands').style.display = st.fcmd ? '' : 'none';
if (ico.classList.contains('icss-garage')) ico.classList.remove('icss-garage'); if (!st.light) document.getElementById('cbHasLight').checked = false;
if (ico.classList.contains('icss-awning')) ico.classList.remove('icss-awning'); if (!st.sun) document.getElementById('cbHasSunsensor').checked = false;
if (ico.classList.contains('icss-lightbulb')) ico.classList.remove('icss-lightbulb'); }
tilt = false;
break;
case 3:
document.getElementById('divTiltSettings').style.display = 'none';
if (ico.classList.contains('icss-window-shade')) ico.classList.remove('icss-window-shade');
if (ico.classList.contains('icss-ldrapery')) ico.classList.remove('icss-ldrapery');
if (ico.classList.contains('icss-rdrapery')) ico.classList.remove('icss-rdrapery');
if (ico.classList.contains('icss-cdrapery')) ico.classList.remove('icss-cdrapery');
if (ico.classList.contains('icss-window-blind')) ico.classList.remove('icss-window-blind');
if (ico.classList.contains('icss-shutter')) ico.classList.remove('icss-shutter');
if (ico.classList.contains('icss-garage')) ico.classList.remove('icss-garage');
if (!ico.classList.contains('icss-awning')) ico.classList.add('icss-awning');
if (ico.classList.contains('icss-lightbulb')) ico.classList.remove('icss-lightbulb');
tilt = false;
break;
case 4:
document.getElementById('divTiltSettings').style.display = 'none';
if (ico.classList.contains('icss-window-shade')) ico.classList.remove('icss-window-shade');
if (ico.classList.contains('icss-ldrapery')) ico.classList.remove('icss-ldrapery');
if (ico.classList.contains('icss-rdrapery')) ico.classList.remove('icss-rdrapery');
if (ico.classList.contains('icss-cdrapery')) ico.classList.remove('icss-cdrapery');
if (ico.classList.contains('icss-window-blind')) ico.classList.remove('icss-window-blind');
if (ico.classList.contains('icss-awning')) ico.classList.remove('icss-awning');
if (ico.classList.contains('icss-garage')) ico.classList.remove('icss-garage');
if (!ico.classList.contains('icss-shutter')) ico.classList.add('icss-shutter');
if (ico.classList.contains('icss-lightbulb')) ico.classList.remove('icss-lightbulb');
tilt = false;
break;
case 5:
flipCommands = false;
case 6:
document.getElementById('divTiltSettings').style.display = 'none';
if (ico.classList.contains('icss-window-shade')) ico.classList.remove('icss-window-shade');
if (ico.classList.contains('icss-ldrapery')) ico.classList.remove('icss-ldrapery');
if (ico.classList.contains('icss-rdrapery')) ico.classList.remove('icss-rdrapery');
if (ico.classList.contains('icss-cdrapery')) ico.classList.remove('icss-cdrapery');
if (ico.classList.contains('icss-window-blind')) ico.classList.remove('icss-window-blind');
if (ico.classList.contains('icss-awning')) ico.classList.remove('icss-awning');
if (ico.classList.contains('icss-shutter')) ico.classList.remove('icss-shutter');
if (!ico.classList.contains('icss-garage')) ico.classList.add('icss-garage');
if (ico.classList.contains('icss-lightbulb')) ico.classList.remove('icss-lightbulb');
light = true;
sun = false;
tilt = false;
break;
case 7:
document.getElementById('divTiltSettings').style.display = 'none';
if (ico.classList.contains('icss-window-shade')) ico.classList.remove('icss-window-shade');
if (ico.classList.contains('icss-ldrapery')) ico.classList.remove('icss-ldrapery');
if (!ico.classList.contains('icss-rdrapery')) ico.classList.add('icss-rdrapery');
if (ico.classList.contains('icss-cdrapery')) ico.classList.remove('icss-cdrapery');
if (ico.classList.contains('icss-window-blind')) ico.classList.remove('icss-window-blind');
if (ico.classList.contains('icss-shutter')) ico.classList.remove('icss-shutter');
if (ico.classList.contains('icss-garage')) ico.classList.remove('icss-garage');
if (ico.classList.contains('icss-awning')) ico.classList.remove('icss-awning');
if (ico.classList.contains('icss-lightbulb')) ico.classList.remove('icss-lightbulb');
tilt = false;
break;
case 8:
document.getElementById('divTiltSettings').style.display = 'none';
if (ico.classList.contains('icss-window-shade')) ico.classList.remove('icss-window-shade');
if (ico.classList.contains('icss-ldrapery')) ico.classList.remove('icss-ldrapery');
if (ico.classList.contains('icss-rdrapery')) ico.classList.remove('icss-rdrapery');
if (!ico.classList.contains('icss-cdrapery')) ico.classList.add('icss-cdrapery');
if (ico.classList.contains('icss-window-blind')) ico.classList.remove('icss-window-blind');
if (ico.classList.contains('icss-shutter')) ico.classList.remove('icss-shutter');
if (ico.classList.contains('icss-garage')) ico.classList.remove('icss-garage');
if (ico.classList.contains('icss-awning')) ico.classList.remove('icss-awning');
if (ico.classList.contains('icss-lightbulb')) ico.classList.remove('icss-lightbulb');
tilt = false;
break;
case 9:
document.getElementById('divTiltSettings').style.display = 'none';
if (ico.classList.contains('icss-window-shade')) ico.classList.remove('icss-window-shade');
if (ico.classList.contains('icss-ldrapery')) ico.classList.remove('icss-ldrapery');
if (ico.classList.contains('icss-rdrapery')) ico.classList.remove('icss-rdrapery');
if (ico.classList.contains('icss-cdrapery')) ico.classList.remove('icss-cdrapery');
if (ico.classList.contains('icss-window-blind')) ico.classList.remove('icss-window-blind');
if (ico.classList.contains('icss-shutter')) ico.classList.remove('icss-shutter');
if (ico.classList.contains('icss-garage')) ico.classList.remove('icss-garage');
if (ico.classList.contains('icss-awning')) ico.classList.remove('icss-awning');
if (!ico.classList.contains('icss-lightbulb')) ico.classList.add('icss-lightbulb');
lift = false;
tilt = false;
light = false;
sun = false;
flipPosition = false;
flipCommands = false;
break;
default:
if (ico.classList.contains('icss-window-blind')) ico.classList.remove('icss-window-blind');
if (ico.classList.contains('icss-awning')) ico.classList.remove('icss-awning');
if (ico.classList.contains('icss-ldrapery')) ico.classList.remove('icss-ldrapery');
if (ico.classList.contains('icss-rdrapery')) ico.classList.remove('icss-rdrapery');
if (ico.classList.contains('icss-cdrapery')) ico.classList.remove('icss-cdrapery');
if (!ico.classList.contains('icss-window-shade')) ico.classList.add('icss-window-shade');
if (ico.classList.contains('icss-garage')) ico.classList.remove('icss-garage');
if (ico.classList.contains('icss-shutter')) ico.classList.remove('icss-shutter');
if (ico.classList.contains('icss-lightbulb')) ico.classList.remove('icss-lightbulb');
document.getElementById('divTiltSettings').style.display = 'none';
tilt = false;
light = false;
break;
} }
document.getElementById('fldTiltTime').parentElement.style.display = tilt ? 'inline-block' : 'none';
if (lift && tilt == 3) lift = false;
document.getElementById('divLiftSettings').style.display = lift ? '' : 'none';
document.querySelector('#divSomfyButtons i.icss-window-tilt').style.display = tilt ? '' : 'none';
document.getElementById('divSunSensor').style.display = sun ? '' : 'none';
document.getElementById('divLightSwitch').style.display = light ? '' : 'none';
document.getElementById('divFlipPosition').style.display = flipPosition ? '' : 'none';
document.getElementById('divFlipCommands').style.display = flipCommands ? '' : 'none';
if (!light) document.getElementById('cbHasLight').checked = false;
if (!sun) document.getElementById('cbHasSunsensor').checked = false;
} }
onShadeBitLengthChanged(el) { onShadeBitLengthChanged(el) {
document.getElementById('somfyShade').setAttribute('data-bitlength', el.value); document.getElementById('somfyShade').setAttribute('data-bitlength', el.value);
@ -2997,54 +2871,15 @@ class Somfy {
document.getElementById('btnLinkRemote').style.display = ''; document.getElementById('btnLinkRemote').style.display = '';
this.onShadeTypeChanged(document.getElementById('selShadeType')); this.onShadeTypeChanged(document.getElementById('selShadeType'));
let ico = document.getElementById('icoShade'); let ico = document.getElementById('icoShade');
switch (shade.shadeType) {
case 0:
document.getElementById('divSunSensor').style.display = '';
break;
case 1:
ico.classList.remove('icss-window-shade');
ico.classList.add('icss-window-blind');
break;
case 2:
ico.classList.remove('icss-window-shade');
ico.classList.add('icss-ldrapery');
document.getElementById('divSunSensor').style.display = '';
break;
case 3:
ico.classList.remove('icss-window-shade');
ico.classList.add('icss-awning');
document.getElementById('divSunSensor').style.display = '';
break;
case 4:
ico.classList.remove('icss-window-shade');
ico.classList.add('icss-shutter');
document.getElementById('divSunSensor').style.display = '';
break;
case 5:
case 6:
ico.classList.remove('icss-window-shade');
ico.classList.add('icss-garage');
document.getElementById('divSunSensor').style.display = 'none';
break;
case 7:
ico.classList.remove('icss-window-shade');
ico.classList.add('icss-rdrapery');
document.getElementById('divSunSensor').style.display = '';
break;
case 8:
ico.classList.remove('icss-window-shade');
ico.classList.add('icss-cdrapery');
document.getElementById('divSunSensor').style.display = '';
break;
}
let tilt = ico.parentElement.querySelector('i.icss-window-tilt'); let tilt = ico.parentElement.querySelector('i.icss-window-tilt');
tilt.style.display = shade.tiltType !== 0 ? '' : 'none'; tilt.style.display = shade.tiltType !== 0 ? '' : 'none';
tilt.setAttribute('data-tiltposition', shade.tiltPosition); tilt.setAttribute('data-tiltposition', shade.tiltPosition);
tilt.setAttribute('data-shadeid', shade.shadeId); tilt.setAttribute('data-shadeid', shade.shadeId);
ico.style.setProperty('--shade-position', `${shade.flipPosition ? 100 - shade.position : shade.position}%`); //ico.style.setProperty('--shade-position', `${shade.flipPosition ? 100 - shade.position : shade.position}%`);
ico.style.setProperty('--tilt-position', `${shade.flipPosition ? 100 - shade.tiltPosition : shade.tiltPosition}%`); //ico.style.setProperty('--tilt-position', `${shade.flipPosition ? 100 - shade.tiltPosition : shade.tiltPosition}%`);
ico.style.setProperty('--shade-position', `${shade.position}%`);
ico.style.setProperty('--tilt-position', `${shade.tiltPosition}%`);
ico.setAttribute('data-shadeid', shade.shadeId); ico.setAttribute('data-shadeid', shade.shadeId);
somfy.onShadeBitLengthChanged(document.getElementById('selShadeBitLength')); somfy.onShadeBitLengthChanged(document.getElementById('selShadeBitLength'));
somfy.onShadeProtoChanged(document.getElementById('selShadeProto')); somfy.onShadeProtoChanged(document.getElementById('selShadeProto'));
@ -3147,6 +2982,7 @@ class Somfy {
if (obj.proto === 8 || obj.proto === 9) { if (obj.proto === 8 || obj.proto === 9) {
switch (obj.shadeType) { switch (obj.shadeType) {
case 5: // Garage 1-button case 5: // Garage 1-button
case 10: // Two button dry contact
if (obj.proto !== 9 && obj.gpioUp === obj.gpioDown) { if (obj.proto !== 9 && obj.gpioUp === obj.gpioDown) {
ui.errorMessage(document.getElementById('divSomfySettings'), 'For GPIO controlled motors the up and down GPIO selections must be unique.'); ui.errorMessage(document.getElementById('divSomfySettings'), 'For GPIO controlled motors the up and down GPIO selections must be unique.');
valid = false; valid = false;
@ -3702,23 +3538,40 @@ class Somfy {
}); });
}); });
let btnPairToGroup = div.querySelector('#btnPairToGroup'); let btnPairToGroup = div.querySelector('#btnPairToGroup');
btnPairToGroup.addEventListener('click', (evt) => { let fnRepeatProgCommand = (err, o) => {
console.log(o);
if (this.btnTimer) {
clearTimeout(this.btnTimer);
this.btnTimer = null;
}
if (err) return;
if (mouseDown) {
if (o.cmd === 'Sensor')
somfy.sendSetSensor(o);
else if (typeof o.groupId !== 'undefined')
somfy.sendGroupRepeat(o.groupId, 'prog', null, fnRepeatProgCommand);
else
somfy.sendCommandRepeat(o.shadeId, 'prog', null, fnRepeatProgCommand);
}
}
btnPairToGroup.addEventListener('mousedown', (evt) => {
mouseDown = true;
somfy.sendGroupCommand(groupId, 'prog', null, fnRepeatProgCommand);
});
btnPairToGroup.addEventListener('mouseup', (evt) => {
mouseDown = false;
let obj = ui.fromElement(div); let obj = ui.fromElement(div);
putJSONSync('/groupCommand', { groupId: groupId, command: 'prog', repeat: 1 }, (err, shade) => { let prompt = ui.promptMessage('Confirm Motor Response', () => {
if (err) ui.serviceError(err); putJSONSync('/linkToGroup', { groupId: groupId, shadeId: obj.shadeId }, (err, group) => {
else { console.log(group);
let prompt = ui.promptMessage('Confirm Motor Response', () => { somfy.setLinkedShadesList(group);
putJSONSync('/linkToGroup', { groupId: groupId, shadeId: obj.shadeId }, (err, group) => { this.updateGroupList();
console.log(group); });
somfy.setLinkedShadesList(group); prompt.remove();
this.updateGroupList(); div.remove();
});
prompt.remove();
div.remove();
});
prompt.querySelector('.sub-message').innerHTML = `<hr></hr><p>Did the shade jog? If the shade jogged press the YES button and your shade will be linked to the group. If it did not press the NO button and try again.</p></p><p>Once the shade has jogged the shade will be added to the group and this process will be finished.</p>`;
}
}); });
prompt.querySelector('.sub-message').innerHTML = `<hr></hr><p>Did the shade jog? If the shade jogged press the YES button and your shade will be linked to the group. If it did not press the NO button and try again.</p></p><p>Once the shade has jogged the shade will be added to the group and this process will be finished.</p>`;
}); });
getJSONSync(`/groupOptions?groupId=${groupId}`, (err, options) => { getJSONSync(`/groupOptions?groupId=${groupId}`, (err, options) => {
if (err) { if (err) {

View file

@ -142,9 +142,25 @@
.shadectl-buttons[data-shadetype="9"] > .button-outline[data-cmd="down"], .shadectl-buttons[data-shadetype="9"] > .button-outline[data-cmd="down"],
.shadectl-buttons[data-shadetype="5"] > .button-outline[data-cmd="my"], .shadectl-buttons[data-shadetype="5"] > .button-outline[data-cmd="my"],
.shadectl-buttons[data-shadetype="5"] > .button-outline[data-cmd="up"], .shadectl-buttons[data-shadetype="5"] > .button-outline[data-cmd="up"],
.shadectl-buttons[data-shadetype="5"] > .button-outline[data-cmd="down"] { .shadectl-buttons[data-shadetype="5"] > .button-outline[data-cmd="down"],
.shadectl-buttons[data-shadetype="10"] > .button-outline[data-cmd="my"] {
display: none; display: none;
} }
.shadectl-buttons[data-shadetype="10"] > .button-outline[data-cmd="up"],
.shadectl-buttons[data-shadetype="10"] > .button-outline[data-cmd="down"] {
width: 3em;
border-radius: 30%;
text-align: center;
height:2.4em;
}
.shadectl-buttons[data-shadetype="10"] > .button-outline[data-cmd="up"] i,
.shadectl-buttons[data-shadetype="10"] > .button-outline[data-cmd="down"] i {
top:.3em;
}
.shadectl-buttons:not([data-shadetype="5"]):not([data-shadetype="9"]) > .button-outline[data-cmd="toggle"] { .shadectl-buttons:not([data-shadetype="5"]):not([data-shadetype="9"]) > .button-outline[data-cmd="toggle"] {
display: none; display: none;
} }
@ -157,9 +173,11 @@
.somfyShadeCtl:not([data-shadetype="1"][data-tilt="3"]) .shadectl-mypos label.my-pos:after { .somfyShadeCtl:not([data-shadetype="1"][data-tilt="3"]) .shadectl-mypos label.my-pos:after {
content: "My:" content: "My:"
} }
.somfyShadeCtl[data-shadetype="1"][data-tilt="3"] .shadectl-mypos label.my-pos { .somfyShadeCtl[data-shadetype="1"][data-tilt="3"] .shadectl-mypos label.my-pos,
display:none; .somfyShadeCtl[data-shadetype="10"] .shadectl-mypos {
display: none;
} }
.somfyShadeCtl[data-shadetype="1"][data-tilt="3"] .shadectl-mypos label.my-pos-tilt:after { .somfyShadeCtl[data-shadetype="1"][data-tilt="3"] .shadectl-mypos label.my-pos-tilt:after {
content:"My Tilt:"; content:"My Tilt:";
} }