mirror of
https://github.com/rstrouse/ESPSomfy-RTS.git
synced 2025-12-13 11:02:12 +01:00
Compare commits
36 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb75868adb | ||
|
|
3d9e6c11c2 | ||
|
|
e478d17c7f | ||
|
|
93ebddd29d | ||
|
|
fb1f18e260 | ||
|
|
c3ada3b40e | ||
|
|
75928b4ac8 | ||
|
|
0b985c0880 | ||
|
|
e04d7e3fc7 | ||
|
|
9205723125 | ||
|
|
2b59f330a9 | ||
|
|
c528fda55a | ||
|
|
f29cd9c089 | ||
|
|
cf7a9b1fc2 | ||
|
|
473307b320 | ||
|
|
2dc49a64e9 | ||
|
|
5f15a7cc93 | ||
|
|
e87f42fa50 | ||
|
|
4f3a93b336 | ||
|
|
6077052e9b | ||
|
|
e3e843387f | ||
|
|
c4e1dbe44b | ||
|
|
23731f793f | ||
|
|
d64103f259 | ||
|
|
2feb420551 | ||
|
|
82c867d2eb | ||
|
|
f8b3bc4133 | ||
|
|
25c8a66869 | ||
|
|
652346a7c7 | ||
|
|
ce3946c9e6 | ||
|
|
c4d6a1008f | ||
|
|
5a8c09ee9f | ||
|
|
026f9315b1 | ||
|
|
6ba354c7ff | ||
|
|
610773c6b7 | ||
|
|
dd0d7fa2a3 |
34 changed files with 2756 additions and 1444 deletions
28
.github/workflows/release.yaml
vendored
28
.github/workflows/release.yaml
vendored
|
|
@ -7,8 +7,8 @@ on:
|
|||
env:
|
||||
ARDUINO_BOARD_MANAGER_ADDITIONAL_URLS: "https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json"
|
||||
ARDUINO_CLI_VERSION: "0.x"
|
||||
ARDUINO_ESP32_VERSION: "2.0.14"
|
||||
ARDUINO_JSON_VERSION: "6.21.3"
|
||||
ARDUINO_ESP32_VERSION: "2.0.17"
|
||||
ARDUINO_JSON_VERSION: "6.21.5"
|
||||
ESPTOOL_VERSION: "4.7"
|
||||
LITTLEFS_VERSION: "v2.5.1"
|
||||
MKLITTLEFS_VERSION: "3.1.0"
|
||||
|
|
@ -30,17 +30,17 @@ jobs:
|
|||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Checkout mklittlefs
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: earlephilhower/mklittlefs
|
||||
path: mklittlefs
|
||||
ref: ${{ env.MKLITTLEFS_VERSION }}
|
||||
|
||||
- name: Checkout LittleFS
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: littlefs-project/littlefs
|
||||
path: mklittlefs/littlefs
|
||||
|
|
@ -55,14 +55,14 @@ jobs:
|
|||
./mklittlefs/mklittlefs --create data --size 1441792 SomfyController.littlefs.bin
|
||||
|
||||
- name: Upload binaries
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: LittleFS
|
||||
path: SomfyController.littlefs.bin
|
||||
retention-days: 5
|
||||
|
||||
- name: Upload LittleFS
|
||||
uses: shogo82148/actions-upload-release-asset@v1.7.2
|
||||
uses: shogo82148/actions-upload-release-asset@v1.7.5
|
||||
with:
|
||||
github_token: ${{ github.token }}
|
||||
upload_url: ${{ steps.get_release.outputs.upload_url }}
|
||||
|
|
@ -91,7 +91,7 @@ jobs:
|
|||
- board: esp32c3
|
||||
addr_bootloader: 0x0
|
||||
chip: ESP32-C3
|
||||
fqbn: esp32:esp32:esp32c3:JTAGAdapter=default,CDCOnBoot=default,PartitionScheme=default,CPUFreq=160,FlashMode=qio,FlashFreq=80,FlashSize=4M,UploadSpeed=921600,DebugLevel=none,EraseFlash=none
|
||||
fqbn: esp32:esp32:esp32c3:JTAGAdapter=default,CDCOnBoot=cdc,PartitionScheme=default,CPUFreq=160,FlashMode=qio,FlashFreq=80,FlashSize=4M,UploadSpeed=921600,DebugLevel=none,EraseFlash=none
|
||||
# esp32:esp32:esp32c3:JTAGAdapter=default,CDCOnBoot=default,PartitionScheme=default,CPUFreq=160,FlashMode=qio,FlashFreq=80,FlashSize=4M,UploadSpeed=921600,DebugLevel=none,EraseFlash=none
|
||||
name: ESP32C3
|
||||
obname: SomfyController.onboard.esp32c3.bin
|
||||
|
|
@ -99,7 +99,7 @@ jobs:
|
|||
- board: esp32s2
|
||||
addr_bootloader: 0x1000
|
||||
chip: ESP32-S2
|
||||
fqbn: esp32:esp32:esp32s2:JTAGAdapter=default,CDCOnBoot=default,MSCOnBoot=default,DFUOnBoot=default,UploadMode=default,PSRAM=disabled,PartitionScheme=default,CPUFreq=240,FlashMode=qio,FlashFreq=80,FlashSize=4M,UploadSpeed=921600,DebugLevel=none,EraseFlash=none
|
||||
fqbn: esp32:esp32:esp32s2:JTAGAdapter=default,CDCOnBoot=cdc,MSCOnBoot=default,DFUOnBoot=default,UploadMode=default,PSRAM=disabled,PartitionScheme=default,CPUFreq=240,FlashMode=qio,FlashFreq=80,FlashSize=4M,UploadSpeed=921600,DebugLevel=none,EraseFlash=none
|
||||
# esp32:esp32:esp32s2:JTAGAdapter=default,CDCOnBoot=default,MSCOnBoot=default,DFUOnBoot=default,UploadMode=default,PSRAM=disabled,PartitionScheme=default,CPUFreq=240,FlashMode=qio,FlashFreq=80,FlashSize=4M,UploadSpeed=921600,DebugLevel=none,EraseFlash=none
|
||||
name: ESP32S2
|
||||
obname: SomfyController.onboard.esp32s2.bin
|
||||
|
|
@ -120,17 +120,17 @@ jobs:
|
|||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: SomfyController
|
||||
|
||||
- name: Get LittleFS
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: LittleFS
|
||||
|
||||
- name: Install Python ${{ env.PYTHON_VERSION }}
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
|
||||
|
|
@ -175,7 +175,7 @@ jobs:
|
|||
0x290000 SomfyController.littlefs.bin
|
||||
|
||||
- name: Upload Firmware ${{ matrix.name }}
|
||||
uses: shogo82148/actions-upload-release-asset@v1.7.2
|
||||
uses: shogo82148/actions-upload-release-asset@v1.7.5
|
||||
with:
|
||||
github_token: ${{ github.token }}
|
||||
upload_url: ${{ steps.get_release.outputs.upload_url }}
|
||||
|
|
@ -187,7 +187,7 @@ jobs:
|
|||
zip ${{ matrix.obname }}.zip ./${{ matrix.obname }}
|
||||
|
||||
- name: Upload Onboard ${{ matrix.name }}
|
||||
uses: shogo82148/actions-upload-release-asset@v1.7.2
|
||||
uses: shogo82148/actions-upload-release-asset@v1.7.5
|
||||
# env:
|
||||
# GITHUB_TOKEN: ${{ github.token }}
|
||||
with:
|
||||
|
|
|
|||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -7,3 +7,4 @@ debug.cfg
|
|||
SomfyController.ino.XIAO_ESP32S3.bin
|
||||
SomfyController.ino.esp32c3.bin
|
||||
SomfyController.ino.esp32s2.bin
|
||||
.vscode/settings.json
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
extern Preferences pref;
|
||||
|
||||
#define SHADE_HDR_VER 22
|
||||
#define SHADE_HDR_VER 24
|
||||
#define SHADE_HDR_SIZE 76
|
||||
#define SHADE_REC_SIZE 276
|
||||
#define GROUP_REC_SIZE 194
|
||||
#define GROUP_REC_SIZE 200
|
||||
#define TRANS_REC_SIZE 74
|
||||
#define ROOM_REC_SIZE 29
|
||||
#define REPEATER_REC_SIZE 77
|
||||
|
|
@ -483,7 +483,7 @@ bool ShadeConfigFile::validate() {
|
|||
if(this->header.version >= 21) {
|
||||
recs = 0;
|
||||
while(recs < this->header.repeaterRecords) {
|
||||
uint32_t pos = this->file.position();
|
||||
//uint32_t pos = this->file.position();
|
||||
if(!this->seekChar(CFG_REC_END)) {
|
||||
Serial.printf("Failed to find the repeater record end %d\n", recs);
|
||||
}
|
||||
|
|
@ -614,7 +614,7 @@ bool ShadeConfigFile::readNetRecord(restore_options_t &opts) {
|
|||
uint32_t startPos = this->file.position();
|
||||
if(opts.network) {
|
||||
Serial.println("Reading network settings from file...");
|
||||
settings.connType = static_cast<conn_types>(this->readUInt8(static_cast<uint8_t>(conn_types::unset)));
|
||||
settings.connType = static_cast<conn_types_t>(this->readUInt8(static_cast<uint8_t>(conn_types_t::unset)));
|
||||
settings.IP.dhcp = this->readBool(true);
|
||||
char ip[24];
|
||||
this->readVarString(ip, sizeof(ip));
|
||||
|
|
@ -728,12 +728,9 @@ bool ShadeConfigFile::readGroupRecord(SomfyGroup *group) {
|
|||
this->readString(group->name, sizeof(group->name));
|
||||
group->proto = static_cast<radio_proto>(this->readUInt8(0));
|
||||
group->bitLength = this->readUInt8(56);
|
||||
if(group->getRemoteAddress() != 0) {
|
||||
uint16_t rc = pref.getUShort(group->getRemotePrefId(), 0);
|
||||
group->lastRollingCode = max(rc, group->lastRollingCode);
|
||||
if(rc < group->lastRollingCode) pref.putUShort(group->getRemotePrefId(), group->lastRollingCode);
|
||||
}
|
||||
if(this->header.version == 23) group->lastRollingCode = this->readUInt16(0);
|
||||
uint8_t lsd = 0;
|
||||
memset(group->linkedShades, 0x00, sizeof(group->linkedShades));
|
||||
for(uint8_t j = 0; j < SOMFY_MAX_GROUPED_SHADES; j++) {
|
||||
uint8_t shadeId = this->readUInt8(0);
|
||||
// Do this to eliminate gaps.
|
||||
|
|
@ -747,6 +744,13 @@ bool ShadeConfigFile::readGroupRecord(SomfyGroup *group) {
|
|||
else group->compressLinkedShadeIds();
|
||||
if(this->header.version >= 18) group->flipCommands = this->readBool(false);
|
||||
if(this->header.version >= 19) group->roomId = this->readUInt8(0);
|
||||
if(this->header.version >= 24) group->lastRollingCode = this->readUInt16(0);
|
||||
if(group->getRemoteAddress() != 0) {
|
||||
uint16_t rc = pref.getUShort(group->getRemotePrefId(), 0);
|
||||
group->lastRollingCode = max(rc, group->lastRollingCode);
|
||||
if(rc < group->lastRollingCode) pref.putUShort(group->getRemotePrefId(), group->lastRollingCode);
|
||||
}
|
||||
|
||||
pref.end();
|
||||
if(this->file.position() != startPos + this->header.groupRecordSize) {
|
||||
Serial.println("Reading to end of group record");
|
||||
|
|
@ -757,7 +761,7 @@ bool ShadeConfigFile::readGroupRecord(SomfyGroup *group) {
|
|||
bool ShadeConfigFile::readRepeaterRecord(SomfyShadeController *s) {
|
||||
uint32_t startPos = this->file.position();
|
||||
|
||||
for(uint8_t i; i < SOMFY_MAX_REPEATERS; i++) {
|
||||
for(uint8_t i = 0; i < SOMFY_MAX_REPEATERS; i++) {
|
||||
s->linkRepeater(this->readUInt32(0));
|
||||
}
|
||||
if(this->file.position() != startPos + this->header.repeaterRecordSize) {
|
||||
|
|
@ -931,7 +935,8 @@ bool ShadeConfigFile::writeGroupRecord(SomfyGroup *group) {
|
|||
this->writeUInt8(group->repeats);
|
||||
this->writeUInt8(group->sortOrder);
|
||||
this->writeBool(group->flipCommands);
|
||||
this->writeUInt8(group->roomId, CFG_REC_END);
|
||||
this->writeUInt8(group->roomId);
|
||||
this->writeUInt16(group->lastRollingCode, CFG_REC_END);
|
||||
return true;
|
||||
}
|
||||
bool ShadeConfigFile::writeRepeaterRecord(SomfyShadeController *s) {
|
||||
|
|
|
|||
|
|
@ -85,6 +85,20 @@ bool appver_t::toJSON(JsonObject &obj) {
|
|||
obj["suffix"] = this->suffix;
|
||||
return true;
|
||||
}
|
||||
void appver_t::toJSON(JsonResponse &json) {
|
||||
json.addElem("name", this->name);
|
||||
json.addElem("major", this->major);
|
||||
json.addElem("minor", this->minor);
|
||||
json.addElem("build", this->build);
|
||||
json.addElem("suffix", this->suffix);
|
||||
}
|
||||
void appver_t::toJSON(JsonSockEvent *json) {
|
||||
json->addElem("name", this->name);
|
||||
json->addElem("major", this->major);
|
||||
json->addElem("minor", this->minor);
|
||||
json->addElem("build", this->build);
|
||||
json->addElem("suffix", this->suffix);
|
||||
}
|
||||
|
||||
bool BaseSettings::load() { return true; }
|
||||
bool BaseSettings::loadFile(const char *filename) {
|
||||
|
|
@ -191,12 +205,12 @@ bool ConfigSettings::load() {
|
|||
pref.getString("hostname", this->hostname, sizeof(this->hostname));
|
||||
this->ssdpBroadcast = pref.getBool("ssdpBroadcast", true);
|
||||
this->checkForUpdate = pref.getBool("checkForUpdate", true);
|
||||
this->connType = static_cast<conn_types>(pref.getChar("connType", 0x00));
|
||||
this->connType = static_cast<conn_types_t>(pref.getChar("connType", 0x00));
|
||||
//Serial.printf("Preference GFG Free Entries: %d\n", pref.freeEntries());
|
||||
pref.end();
|
||||
if(this->connType == conn_types::unset) {
|
||||
if(this->connType == conn_types_t::unset) {
|
||||
// We are doing this to convert the data from previous versions.
|
||||
this->connType = conn_types::wifi;
|
||||
this->connType = conn_types_t::wifi;
|
||||
pref.begin("WIFI");
|
||||
pref.getString("hostname", this->hostname, sizeof(this->hostname));
|
||||
this->ssdpBroadcast = pref.getBool("ssdpBroadcast", true);
|
||||
|
|
@ -235,11 +249,19 @@ bool ConfigSettings::toJSON(JsonObject &obj) {
|
|||
obj["checkForUpdate"] = this->checkForUpdate;
|
||||
return true;
|
||||
}
|
||||
void ConfigSettings::toJSON(JsonResponse &json) {
|
||||
json.addElem("ssdpBroadcast", this->ssdpBroadcast);
|
||||
json.addElem("hostname", this->hostname);
|
||||
json.addElem("connType", static_cast<uint8_t>(this->connType));
|
||||
json.addElem("chipModel", this->chipModel);
|
||||
json.addElem("checkForUpdate", this->checkForUpdate);
|
||||
}
|
||||
|
||||
bool ConfigSettings::requiresAuth() { return this->Security.type != security_types::None; }
|
||||
bool ConfigSettings::fromJSON(JsonObject &obj) {
|
||||
if(obj.containsKey("ssdpBroadcast")) this->ssdpBroadcast = obj["ssdpBroadcast"];
|
||||
if(obj.containsKey("hostname")) this->parseValueString(obj, "hostname", this->hostname, sizeof(this->hostname));
|
||||
if(obj.containsKey("connType")) this->connType = static_cast<conn_types>(obj["connType"].as<uint8_t>());
|
||||
if(obj.containsKey("connType")) this->connType = static_cast<conn_types_t>(obj["connType"].as<uint8_t>());
|
||||
if(obj.containsKey("checkForUpdate")) this->checkForUpdate = obj["checkForUpdate"];
|
||||
return true;
|
||||
}
|
||||
|
|
@ -247,8 +269,8 @@ void ConfigSettings::print() {
|
|||
this->Security.print();
|
||||
Serial.printf("Connection Type: %u\n", (unsigned int) this->connType);
|
||||
this->NTP.print();
|
||||
if(this->connType == conn_types::wifi || this->connType == conn_types::unset) this->WIFI.print();
|
||||
if(this->connType == conn_types::ethernet || this->connType == conn_types::ethernetpref) this->Ethernet.print();
|
||||
if(this->connType == conn_types_t::wifi || this->connType == conn_types_t::unset) this->WIFI.print();
|
||||
if(this->connType == conn_types_t::ethernet || this->connType == conn_types_t::ethernetpref) this->Ethernet.print();
|
||||
}
|
||||
void ConfigSettings::emitSockets() {}
|
||||
void ConfigSettings::emitSockets(uint8_t num) {}
|
||||
|
|
@ -286,6 +308,18 @@ bool MQTTSettings::begin() {
|
|||
this->load();
|
||||
return true;
|
||||
}
|
||||
void MQTTSettings::toJSON(JsonResponse &json) {
|
||||
json.addElem("enabled", this->enabled);
|
||||
json.addElem("pubDisco", this->pubDisco);
|
||||
json.addElem("protocol", this->protocol);
|
||||
json.addElem("hostname", this->hostname);
|
||||
json.addElem("port", (uint32_t)this->port);
|
||||
json.addElem("username", this->username);
|
||||
json.addElem("password", this->password);
|
||||
json.addElem("rootTopic", this->rootTopic);
|
||||
json.addElem("discoTopic", this->discoTopic);
|
||||
}
|
||||
|
||||
bool MQTTSettings::toJSON(JsonObject &obj) {
|
||||
obj["enabled"] = this->enabled;
|
||||
obj["pubDisco"] = this->pubDisco;
|
||||
|
|
@ -384,6 +418,11 @@ bool NTPSettings::fromJSON(JsonObject &obj) {
|
|||
this->parseValueString(obj, "posixZone", this->posixZone, sizeof(this->posixZone));
|
||||
return true;
|
||||
}
|
||||
void NTPSettings::toJSON(JsonResponse &json) {
|
||||
json.addElem("ntpServer", this->ntpServer);
|
||||
json.addElem("posixZone", this->posixZone);
|
||||
}
|
||||
|
||||
bool NTPSettings::toJSON(JsonObject &obj) {
|
||||
obj["ntpServer"] = this->ntpServer;
|
||||
obj["posixZone"] = this->posixZone;
|
||||
|
|
@ -420,6 +459,16 @@ bool IPSettings::toJSON(JsonObject &obj) {
|
|||
obj["dns2"] = this->dns2 == ipEmpty ? "" : this->dns2.toString();
|
||||
return true;
|
||||
}
|
||||
void IPSettings::toJSON(JsonResponse &json) {
|
||||
IPAddress ipEmpty(0,0,0,0);
|
||||
json.addElem("dhcp", this->dhcp);
|
||||
json.addElem("ip", this->ip.toString().c_str());
|
||||
json.addElem("gateway", this->gateway.toString().c_str());
|
||||
json.addElem("subnet", this->subnet.toString().c_str());
|
||||
json.addElem("dns1", this->dns1.toString().c_str());
|
||||
json.addElem("dns2", this->dns2.toString().c_str());
|
||||
}
|
||||
|
||||
bool IPSettings::save() {
|
||||
pref.begin("IP");
|
||||
pref.clear();
|
||||
|
|
@ -480,6 +529,14 @@ bool SecuritySettings::toJSON(JsonObject &obj) {
|
|||
obj["permissions"] = this->permissions;
|
||||
return true;
|
||||
}
|
||||
void SecuritySettings::toJSON(JsonResponse &json) {
|
||||
json.addElem("type", static_cast<uint8_t>(this->type));
|
||||
json.addElem("username", this->username);
|
||||
json.addElem("password", this->password);
|
||||
json.addElem("pin", this->pin);
|
||||
json.addElem("permissions", this->permissions);
|
||||
}
|
||||
|
||||
bool SecuritySettings::save() {
|
||||
pref.begin("SEC");
|
||||
pref.clear();
|
||||
|
|
@ -523,20 +580,30 @@ bool WifiSettings::fromJSON(JsonObject &obj) {
|
|||
this->parseValueString(obj, "ssid", this->ssid, sizeof(this->ssid));
|
||||
this->parseValueString(obj, "passphrase", this->passphrase, sizeof(this->passphrase));
|
||||
if(obj.containsKey("roaming")) this->roaming = obj["roaming"];
|
||||
if(obj.containsKey("hidden")) this->hidden = obj["hidden"];
|
||||
return true;
|
||||
}
|
||||
bool WifiSettings::toJSON(JsonObject &obj) {
|
||||
obj["ssid"] = this->ssid;
|
||||
obj["passphrase"] = this->passphrase;
|
||||
obj["roaming"] = this->roaming;
|
||||
obj["hidden"] = this->hidden;
|
||||
return true;
|
||||
}
|
||||
void WifiSettings::toJSON(JsonResponse &json) {
|
||||
json.addElem("ssid", this->ssid);
|
||||
json.addElem("passphrase", this->passphrase);
|
||||
json.addElem("roaming", this->roaming);
|
||||
json.addElem("hidden", this->hidden);
|
||||
}
|
||||
|
||||
bool WifiSettings::save() {
|
||||
pref.begin("WIFI");
|
||||
pref.clear();
|
||||
pref.putString("ssid", this->ssid);
|
||||
pref.putString("passphrase", this->passphrase);
|
||||
pref.putBool("roaming", this->roaming);
|
||||
pref.putBool("hidden", this->hidden);
|
||||
pref.end();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -547,6 +614,7 @@ bool WifiSettings::load() {
|
|||
this->ssid[sizeof(this->ssid) - 1] = '\0';
|
||||
this->passphrase[sizeof(this->passphrase) - 1] = '\0';
|
||||
this->roaming = pref.getBool("roaming", true);
|
||||
this->hidden = pref.getBool("hidden", false);
|
||||
pref.end();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -595,6 +663,7 @@ void WifiSettings::printNetworks() {
|
|||
Serial.print(WiFi.BSSIDstr(i));
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
}
|
||||
bool WifiSettings::ssidExists(const char *ssid) {
|
||||
int n = WiFi.scanNetworks(false, true);
|
||||
|
|
@ -628,6 +697,16 @@ bool EthernetSettings::toJSON(JsonObject &obj) {
|
|||
obj["MDIOPin"] = this->MDIOPin;
|
||||
return true;
|
||||
}
|
||||
void EthernetSettings::toJSON(JsonResponse &json) {
|
||||
json.addElem("boardType", this->boardType);
|
||||
json.addElem("phyAddress", this->phyAddress);
|
||||
json.addElem("CLKMode", static_cast<uint8_t>(this->CLKMode));
|
||||
json.addElem("phyType", static_cast<uint8_t>(this->phyType));
|
||||
json.addElem("PWRPin", this->PWRPin);
|
||||
json.addElem("MDCPin", this->MDCPin);
|
||||
json.addElem("MDIOPin", this->MDIOPin);
|
||||
}
|
||||
|
||||
bool EthernetSettings::usesPin(uint8_t pin) {
|
||||
if((this->CLKMode == 0 || this->CLKMode == 1) && pin == 0) return true;
|
||||
else if(this->CLKMode == 2 && pin == 16) return true;
|
||||
|
|
|
|||
|
|
@ -2,8 +2,16 @@
|
|||
#include <ETH.h>
|
||||
#ifndef configsettings_h
|
||||
#define configsettings_h
|
||||
#include "WResp.h"
|
||||
#define FW_VERSION "v2.4.7"
|
||||
enum class conn_types_t : byte {
|
||||
unset = 0x00,
|
||||
wifi = 0x01,
|
||||
ethernet = 0x02,
|
||||
ethernetpref = 0x03,
|
||||
ap = 0x04
|
||||
};
|
||||
|
||||
#define FW_VERSION "v2.4.1"
|
||||
enum DeviceStatus {
|
||||
DS_OK = 0,
|
||||
DS_ERROR = 1,
|
||||
|
|
@ -26,6 +34,8 @@ struct appver_t {
|
|||
char suffix[4] = "";
|
||||
void parse(const char *ver);
|
||||
bool toJSON(JsonObject &obj);
|
||||
void toJSON(JsonResponse &json);
|
||||
void toJSON(JsonSockEvent *json);
|
||||
int8_t compare(appver_t &ver);
|
||||
void copy(appver_t &ver);
|
||||
};
|
||||
|
|
@ -36,6 +46,7 @@ class BaseSettings {
|
|||
bool loadFile(const char* filename);
|
||||
bool fromJSON(JsonObject &obj);
|
||||
bool toJSON(JsonObject &obj);
|
||||
void toJSON(JsonResponse &json);
|
||||
bool parseIPAddress(JsonObject &obj, const char *prop, IPAddress *);
|
||||
bool parseValueString(JsonObject &obj, const char *prop, char *dest, size_t size);
|
||||
int parseValueInt(JsonObject &obj, const char *prop, int defVal);
|
||||
|
|
@ -50,6 +61,7 @@ class NTPSettings: BaseSettings {
|
|||
char posixZone[64] = "";
|
||||
bool fromJSON(JsonObject &obj);
|
||||
bool toJSON(JsonObject &obj);
|
||||
void toJSON(JsonResponse &json);
|
||||
bool apply();
|
||||
bool begin();
|
||||
bool save();
|
||||
|
|
@ -60,12 +72,14 @@ class WifiSettings: BaseSettings {
|
|||
public:
|
||||
WifiSettings();
|
||||
bool roaming = true;
|
||||
bool hidden = false;
|
||||
char ssid[65] = "";
|
||||
char passphrase[65] = "";
|
||||
//bool ssdpBroadcast = true;
|
||||
bool begin();
|
||||
bool fromJSON(JsonObject &obj);
|
||||
bool toJSON(JsonObject &obj);
|
||||
void toJSON(JsonResponse &json);
|
||||
String mapEncryptionType(int type);
|
||||
bool ssidExists(const char *ssid);
|
||||
void printNetworks();
|
||||
|
|
@ -88,6 +102,7 @@ class EthernetSettings: BaseSettings {
|
|||
bool begin();
|
||||
bool fromJSON(JsonObject &obj);
|
||||
bool toJSON(JsonObject &obj);
|
||||
void toJSON(JsonResponse &json);
|
||||
bool load();
|
||||
bool save();
|
||||
void print();
|
||||
|
|
@ -105,6 +120,7 @@ class IPSettings: BaseSettings {
|
|||
bool begin();
|
||||
bool fromJSON(JsonObject &obj);
|
||||
bool toJSON(JsonObject &obj);
|
||||
void toJSON(JsonResponse &json);
|
||||
bool load();
|
||||
bool save();
|
||||
void print();
|
||||
|
|
@ -129,6 +145,7 @@ class SecuritySettings: BaseSettings {
|
|||
bool load();
|
||||
void print();
|
||||
bool toJSON(JsonObject &obj);
|
||||
void toJSON(JsonResponse &json);
|
||||
bool fromJSON(JsonObject &obj);
|
||||
};
|
||||
class MQTTSettings: BaseSettings {
|
||||
|
|
@ -146,21 +163,16 @@ class MQTTSettings: BaseSettings {
|
|||
bool save();
|
||||
bool load();
|
||||
bool toJSON(JsonObject &obj);
|
||||
void toJSON(JsonResponse &json);
|
||||
bool fromJSON(JsonObject &obj);
|
||||
};
|
||||
enum class conn_types : byte {
|
||||
unset = 0x00,
|
||||
wifi = 0x01,
|
||||
ethernet = 0x02,
|
||||
ethernetpref = 0x03
|
||||
};
|
||||
class ConfigSettings: BaseSettings {
|
||||
public:
|
||||
static void printAvailHeap();
|
||||
char serverId[10] = "";
|
||||
char hostname[32] = "ESPSomfyRTS";
|
||||
char chipModel[10] = "ESP32";
|
||||
conn_types connType = conn_types::unset;
|
||||
conn_types_t connType = conn_types_t::unset;
|
||||
appver_t fwVersion;
|
||||
appver_t appVersion;
|
||||
bool ssdpBroadcast = true;
|
||||
|
|
@ -175,6 +187,7 @@ class ConfigSettings: BaseSettings {
|
|||
bool requiresAuth();
|
||||
bool fromJSON(JsonObject &obj);
|
||||
bool toJSON(JsonObject &obj);
|
||||
void toJSON(JsonResponse &json);
|
||||
bool begin();
|
||||
bool save();
|
||||
bool load();
|
||||
|
|
@ -186,5 +199,4 @@ class ConfigSettings: BaseSettings {
|
|||
uint16_t calcNetRecSize();
|
||||
bool getAppVersion();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
379
GitOTA.cpp
379
GitOTA.cpp
|
|
@ -2,12 +2,17 @@
|
|||
#include <WiFiClientSecure.h>
|
||||
#include <Update.h>
|
||||
#include <HTTPClient.h>
|
||||
#include <esp_task_wdt.h>
|
||||
#include "ConfigSettings.h"
|
||||
#include "GitOTA.h"
|
||||
#include "Utils.h"
|
||||
#include "ConfigSettings.h"
|
||||
#include "Sockets.h"
|
||||
#include "Somfy.h"
|
||||
#include "Web.h"
|
||||
#include "WResp.h"
|
||||
#include "Network.h"
|
||||
|
||||
|
||||
|
||||
|
||||
extern ConfigSettings settings;
|
||||
|
|
@ -15,6 +20,8 @@ extern SocketEmitter sockEmit;
|
|||
extern SomfyShadeController somfy;
|
||||
extern rebootDelay_t rebootDelay;
|
||||
extern Web webServer;
|
||||
extern Network net;
|
||||
|
||||
|
||||
|
||||
#define MAX_BUFF_SIZE 4096
|
||||
|
|
@ -65,19 +72,21 @@ void GitRelease::setAssetProperty(const char *key, const char *val) {
|
|||
}
|
||||
}
|
||||
}
|
||||
bool GitRelease::toJSON(JsonObject &obj) {
|
||||
void GitRelease::toJSON(JsonResponse &json) {
|
||||
Timestamp ts;
|
||||
obj["id"] = this->id;
|
||||
obj["name"] = this->name;
|
||||
obj["date"] = ts.getISOTime(this->releaseDate);
|
||||
obj["draft"] = this->draft;
|
||||
obj["preRelease"] = this->preRelease;
|
||||
obj["main"] = this->main;
|
||||
obj["hasFS"] = this->hasFS;
|
||||
obj["hwVersions"] = this->hwVersions;
|
||||
JsonObject ver = obj.createNestedObject("version");
|
||||
this->version.toJSON(ver);
|
||||
return true;
|
||||
char buff[20];
|
||||
sprintf(buff, "%llu", this->id);
|
||||
json.addElem("id", buff);
|
||||
json.addElem("name", this->name);
|
||||
json.addElem("date", ts.getISOTime(this->releaseDate));
|
||||
json.addElem("draft", this->draft);
|
||||
json.addElem("preRelease", this->preRelease);
|
||||
json.addElem("main", this->main);
|
||||
json.addElem("hasFS", this->hasFS);
|
||||
json.addElem("hwVersions", this->hwVersions);
|
||||
json.beginObject("version");
|
||||
this->version.toJSON(json);
|
||||
json.endObject();
|
||||
}
|
||||
#define ERR_CLIENT_OFFSET -50
|
||||
|
||||
|
|
@ -97,16 +106,17 @@ int16_t GitRepo::getReleases(uint8_t num) {
|
|||
strcpy(main->version.name, "main");
|
||||
strcpy(main->name, "Main");
|
||||
strcpy(main->hwVersions, "32,s3");
|
||||
HTTPClient *https = new HTTPClient();
|
||||
https->setReuse(false);
|
||||
if(https->begin(sclient, url)) {
|
||||
int httpCode = https->GET();
|
||||
HTTPClient https;
|
||||
https.setReuse(false);
|
||||
if(https.begin(sclient, url)) {
|
||||
esp_task_wdt_reset();
|
||||
int httpCode = https.GET();
|
||||
Serial.printf("[HTTPS] GET... code: %d\n", httpCode);
|
||||
if(httpCode > 0) {
|
||||
int len = https->getSize();
|
||||
int len = https.getSize();
|
||||
Serial.printf("[HTTPS] GET... code: %d - %d\n", httpCode, len);
|
||||
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
|
||||
WiFiClient *stream = https->getStreamPtr();
|
||||
WiFiClient *stream = https.getStreamPtr();
|
||||
uint8_t buff[128] = {0};
|
||||
char jsonElem[32] = "";
|
||||
char jsonValue[128] = "";
|
||||
|
|
@ -117,9 +127,10 @@ int16_t GitRepo::getReleases(uint8_t num) {
|
|||
bool inValue = false;
|
||||
bool awaitValue = false;
|
||||
bool inAss = false;
|
||||
while(https->connected() && (len > 0 || len == -1) && ndx < count) {
|
||||
while(https.connected() && (len > 0 || len == -1) && ndx < count) {
|
||||
size_t size = stream->available();
|
||||
if(size) {
|
||||
esp_task_wdt_reset();
|
||||
int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
|
||||
//Serial.write(buff, c);
|
||||
if(len > 0) len -= c;
|
||||
|
|
@ -208,31 +219,32 @@ int16_t GitRepo::getReleases(uint8_t num) {
|
|||
}
|
||||
}
|
||||
else {
|
||||
https->end();
|
||||
https.end();
|
||||
sclient.stop();
|
||||
delete https;
|
||||
return httpCode;
|
||||
}
|
||||
}
|
||||
https->end();
|
||||
delete https;
|
||||
https.end();
|
||||
sclient.stop();
|
||||
}
|
||||
sclient.stop();
|
||||
settings.printAvailHeap();
|
||||
return 0;
|
||||
}
|
||||
bool GitRepo::toJSON(JsonObject &obj) {
|
||||
JsonObject fw = obj.createNestedObject("fwVersion");
|
||||
settings.fwVersion.toJSON(fw);
|
||||
JsonObject app = obj.createNestedObject("appVersion");
|
||||
settings.appVersion.toJSON(app);
|
||||
JsonArray arr = obj.createNestedArray("releases");
|
||||
void GitRepo::toJSON(JsonResponse &json) {
|
||||
json.beginObject("fwVersion");
|
||||
settings.fwVersion.toJSON(json);
|
||||
json.endObject();
|
||||
json.beginObject("appVersion");
|
||||
settings.appVersion.toJSON(json);
|
||||
json.endObject();
|
||||
json.beginArray("releases");
|
||||
for(uint8_t i = 0; i < GIT_MAX_RELEASES + 1; i++) {
|
||||
if(this->releases[i].id == 0) continue;
|
||||
JsonObject o = arr.createNestedObject();
|
||||
this->releases[i].toJSON(o);
|
||||
json.beginObject();
|
||||
this->releases[i].toJSON(json);
|
||||
json.endObject();
|
||||
}
|
||||
return true;
|
||||
json.endArray();
|
||||
}
|
||||
#define UPDATE_ERR_OFFSET 20
|
||||
#define ERR_DOWNLOAD_HTTP -40
|
||||
|
|
@ -240,12 +252,10 @@ bool GitRepo::toJSON(JsonObject &obj) {
|
|||
#define ERR_DOWNLOAD_CONNECTION -42
|
||||
|
||||
void GitUpdater::loop() {
|
||||
if(!net.connected()) return;
|
||||
if(this->status == GIT_STATUS_READY) {
|
||||
//if(this->lastCheck == 0)
|
||||
//this->lastCheck = millis();
|
||||
//else
|
||||
if(settings.checkForUpdate &&
|
||||
//(this->lastCheck + 14400000 < millis() || this->lastCheck == 0) && !rebootDelay.reboot) { // 4 hours
|
||||
(millis() > net.connectTime + 60000) && // Wait a minute before checking after connection.
|
||||
(this->lastCheck + 86400000 < millis() || this->lastCheck == 0) && !rebootDelay.reboot) { // 1 day
|
||||
this->checkForUpdate();
|
||||
}
|
||||
|
|
@ -269,6 +279,7 @@ void GitUpdater::loop() {
|
|||
void GitUpdater::checkForUpdate() {
|
||||
if(this->status != 0) return; // If we are already checking.
|
||||
Serial.println("Check github for updates...");
|
||||
|
||||
this->status = GIT_STATUS_CHECK;
|
||||
settings.printAvailHeap();
|
||||
this->lastCheck = millis();
|
||||
|
|
@ -299,42 +310,59 @@ void GitUpdater::setCurrentRelease(GitRepo &repo) {
|
|||
}
|
||||
this->emitUpdateCheck();
|
||||
}
|
||||
void GitUpdater::toJSON(JsonObject &obj) {
|
||||
obj["available"] = this->updateAvailable;
|
||||
obj["status"] = this->status;
|
||||
obj["error"] = this->error;
|
||||
obj["cancelled"] = this->cancelled;
|
||||
obj["checkForUpdate"] = settings.checkForUpdate;
|
||||
obj["inetAvailable"] = this->inetAvailable;
|
||||
JsonObject fw = obj.createNestedObject("fwVersion");
|
||||
settings.fwVersion.toJSON(fw);
|
||||
JsonObject app = obj.createNestedObject("appVersion");
|
||||
settings.appVersion.toJSON(app);
|
||||
JsonObject latest = obj.createNestedObject("latest");
|
||||
this->latest.toJSON(latest);
|
||||
void GitUpdater::toJSON(JsonResponse &json) {
|
||||
json.addElem("available", this->updateAvailable);
|
||||
json.addElem("status", this->status);
|
||||
json.addElem("error", (int32_t)this->error);
|
||||
json.addElem("cancelled", this->cancelled);
|
||||
json.addElem("checkForUpdate", settings.checkForUpdate);
|
||||
json.addElem("inetAvailable", this->inetAvailable);
|
||||
json.beginObject("fwVersion");
|
||||
settings.fwVersion.toJSON(json);
|
||||
json.endObject();
|
||||
json.beginObject("appVersion");
|
||||
settings.appVersion.toJSON(json);
|
||||
json.endObject();
|
||||
json.beginObject("latest");
|
||||
this->latest.toJSON(json);
|
||||
json.endObject();
|
||||
}
|
||||
void GitUpdater::emitUpdateCheck(uint8_t num) {
|
||||
ClientSocketEvent evt("fwStatus");
|
||||
DynamicJsonDocument doc(512);
|
||||
JsonObject obj = doc.to<JsonObject>();
|
||||
this->toJSON(obj);
|
||||
if(num == 255)
|
||||
sockEmit.sendToClients("fwStatus", doc);
|
||||
else
|
||||
sockEmit.sendToClient(num, "fwStatus", doc);
|
||||
JsonSockEvent *json = sockEmit.beginEmit("fwStatus");
|
||||
json->beginObject();
|
||||
json->addElem("available", this->updateAvailable);
|
||||
json->addElem("status", this->status);
|
||||
json->addElem("error", (int32_t)this->error);
|
||||
json->addElem("cancelled", this->cancelled);
|
||||
json->addElem("checkForUpdate", settings.checkForUpdate);
|
||||
json->addElem("inetAvailable", this->inetAvailable);
|
||||
json->beginObject("fwVersion");
|
||||
settings.fwVersion.toJSON(json);
|
||||
json->endObject();
|
||||
json->beginObject("appVersion");
|
||||
settings.appVersion.toJSON(json);
|
||||
json->endObject();
|
||||
json->beginObject("latest");
|
||||
this->latest.toJSON(json);
|
||||
json->endObject();
|
||||
json->endObject();
|
||||
sockEmit.endEmit(num);
|
||||
}
|
||||
int GitUpdater::checkInternet() {
|
||||
int err = 500;
|
||||
uint32_t t = millis();
|
||||
WiFiClientSecure client;
|
||||
client.setInsecure();
|
||||
client.setHandshakeTimeout(3);
|
||||
HTTPClient *https = new HTTPClient();
|
||||
https->setReuse(false);
|
||||
if(https->begin(client, "https://github.com/rstrouse/ESPSomfy-RTS")) {
|
||||
https->setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS);
|
||||
https->setTimeout(5000);
|
||||
int httpCode = https->sendRequest("HEAD");
|
||||
WiFiClientSecure sclient;
|
||||
sclient.setInsecure();
|
||||
sclient.setHandshakeTimeout(3);
|
||||
esp_task_wdt_reset();
|
||||
HTTPClient https;
|
||||
https.setReuse(false);
|
||||
if(https.begin(sclient, "https://github.com/rstrouse/ESPSomfy-RTS")) {
|
||||
https.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS);
|
||||
https.setTimeout(3000);
|
||||
esp_task_wdt_reset();
|
||||
int httpCode = https.sendRequest("HEAD");
|
||||
esp_task_wdt_reset();
|
||||
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY || httpCode == HTTP_CODE_FOUND) {
|
||||
err = 0;
|
||||
Serial.printf("Internet is Available: %ldms\n", millis() - t);
|
||||
|
|
@ -345,18 +373,30 @@ int GitUpdater::checkInternet() {
|
|||
Serial.printf("Internet is Unavailable: %d: %ldms\n", err, millis() - t);
|
||||
this->inetAvailable = false;
|
||||
}
|
||||
https->end();
|
||||
https.end();
|
||||
sclient.stop();
|
||||
}
|
||||
client.stop();
|
||||
delete https;
|
||||
esp_task_wdt_reset();
|
||||
return err;
|
||||
}
|
||||
void GitUpdater::emitDownloadProgress(size_t total, size_t loaded, const char *evt) { this->emitDownloadProgress(255, total, loaded, evt); }
|
||||
void GitUpdater::emitDownloadProgress(uint8_t num, size_t total, size_t loaded, const char *evt) {
|
||||
JsonSockEvent *json = sockEmit.beginEmit(evt);
|
||||
json->beginObject();
|
||||
json->addElem("ver", this->targetRelease);
|
||||
json->addElem("part", (int32_t)this->partition);
|
||||
json->addElem("file", this->currentFile);
|
||||
json->addElem("total", (uint32_t)total);
|
||||
json->addElem("loaded", (uint32_t)loaded);
|
||||
json->addElem("error", (uint32_t)this->error);
|
||||
json->endObject();
|
||||
sockEmit.endEmit(num);
|
||||
/*
|
||||
char buf[420];
|
||||
snprintf(buf, sizeof(buf), "{\"ver\":\"%s\",\"part\":%d,\"file\":\"%s\",\"total\":%d,\"loaded\":%d, \"error\":%d}", this->targetRelease, this->partition, this->currentFile, total, loaded, this->error);
|
||||
if(num >= 255) sockEmit.sendToClients(evt, buf);
|
||||
else sockEmit.sendToClient(num, evt, buf);
|
||||
*/
|
||||
sockEmit.loop();
|
||||
webServer.loop();
|
||||
}
|
||||
|
|
@ -431,119 +471,118 @@ bool GitUpdater::recoverFilesystem() {
|
|||
}
|
||||
bool GitUpdater::endUpdate() { return true; }
|
||||
int8_t GitUpdater::downloadFile() {
|
||||
WiFiClientSecure *client = new WiFiClientSecure;
|
||||
Serial.printf("Begin update %s\n", this->currentFile);
|
||||
if(client) {
|
||||
client->setInsecure();
|
||||
HTTPClient https;
|
||||
char url[196];
|
||||
sprintf(url, "%s%s", this->baseUrl, this->currentFile);
|
||||
Serial.println(url);
|
||||
if(https.begin(*client, url)) {
|
||||
https.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS);
|
||||
Serial.print("[HTTPS] GET...\n");
|
||||
int httpCode = https.GET();
|
||||
if(httpCode > 0) {
|
||||
size_t len = https.getSize();
|
||||
size_t total = 0;
|
||||
uint8_t pct = 0;
|
||||
Serial.printf("[HTTPS] GET... code: %d - %d\n", httpCode, len);
|
||||
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY || httpCode == HTTP_CODE_FOUND) {
|
||||
WiFiClient *stream = https.getStreamPtr();
|
||||
if(!Update.begin(len, this->partition)) {
|
||||
Serial.println("Update Error detected!!!!!");
|
||||
Update.printError(Serial);
|
||||
https.end();
|
||||
return -(Update.getError() + UPDATE_ERR_OFFSET);
|
||||
}
|
||||
uint8_t *buff = (uint8_t *)malloc(MAX_BUFF_SIZE);
|
||||
if(buff) {
|
||||
this->emitDownloadProgress(len, total);
|
||||
int timeouts = 0;
|
||||
while(https.connected() && (len > 0 || len == -1) && total < len) {
|
||||
size_t size = stream->available();
|
||||
if(size) {
|
||||
if(this->cancelled && !this->lockFS) {
|
||||
Update.abort();
|
||||
https.end();
|
||||
free(buff);
|
||||
return -(Update.getError() + UPDATE_ERR_OFFSET);
|
||||
}
|
||||
int c = stream->readBytes(buff, ((size > MAX_BUFF_SIZE) ? MAX_BUFF_SIZE : size));
|
||||
total += c;
|
||||
//Serial.println(total);
|
||||
if (Update.write(buff, c) != c) {
|
||||
WiFiClientSecure sclient;
|
||||
sclient.setInsecure();
|
||||
HTTPClient https;
|
||||
char url[196];
|
||||
sprintf(url, "%s%s", this->baseUrl, this->currentFile);
|
||||
Serial.println(url);
|
||||
esp_task_wdt_reset();
|
||||
if(https.begin(sclient, url)) {
|
||||
https.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS);
|
||||
Serial.print("[HTTPS] GET...\n");
|
||||
int httpCode = https.GET();
|
||||
if(httpCode > 0) {
|
||||
size_t len = https.getSize();
|
||||
size_t total = 0;
|
||||
uint8_t pct = 0;
|
||||
Serial.printf("[HTTPS] GET... code: %d - %d\n", httpCode, len);
|
||||
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY || httpCode == HTTP_CODE_FOUND) {
|
||||
WiFiClient *stream = https.getStreamPtr();
|
||||
if(!Update.begin(len, this->partition)) {
|
||||
Serial.println("Update Error detected!!!!!");
|
||||
Update.printError(Serial);
|
||||
https.end();
|
||||
return -(Update.getError() + UPDATE_ERR_OFFSET);
|
||||
}
|
||||
uint8_t *buff = (uint8_t *)malloc(MAX_BUFF_SIZE);
|
||||
if(buff) {
|
||||
this->emitDownloadProgress(len, total);
|
||||
int timeouts = 0;
|
||||
while(https.connected() && (len > 0 || len == -1) && total < len) {
|
||||
size_t size = stream->available();
|
||||
esp_task_wdt_reset();
|
||||
if(size) {
|
||||
timeouts = 0;
|
||||
if(this->cancelled && !this->lockFS) {
|
||||
Update.abort();
|
||||
free(buff);
|
||||
https.end();
|
||||
return -(Update.getError() + UPDATE_ERR_OFFSET);
|
||||
}
|
||||
int c = stream->readBytes(buff, ((size > MAX_BUFF_SIZE) ? MAX_BUFF_SIZE : size));
|
||||
total += c;
|
||||
//Serial.println(total);
|
||||
if (Update.write(buff, c) != c) {
|
||||
Update.printError(Serial);
|
||||
Serial.printf("Upload of %s aborted invalid size %d\n", url, c);
|
||||
free(buff);
|
||||
https.end();
|
||||
sclient.stop();
|
||||
return -(Update.getError() + UPDATE_ERR_OFFSET);
|
||||
}
|
||||
// Calculate the percentage.
|
||||
uint8_t p = (uint8_t)floor(((float)total / (float)len) * 100.0f);
|
||||
if(p != pct) {
|
||||
pct = p;
|
||||
Serial.printf("LEN:%d TOTAL:%d %d%%\n", len, total, pct);
|
||||
this->emitDownloadProgress(len, total);
|
||||
}
|
||||
delay(1);
|
||||
if(total >= len) {
|
||||
if(!Update.end(true)) {
|
||||
Serial.println("Error downloading update...");
|
||||
Update.printError(Serial);
|
||||
Serial.printf("Upload of %s aborted invalid size %d\n", url, c);
|
||||
free(buff);
|
||||
https.end();
|
||||
return -(Update.getError() + UPDATE_ERR_OFFSET);
|
||||
}
|
||||
// Calculate the percentage.
|
||||
uint8_t p = (uint8_t)floor(((float)total / (float)len) * 100.0f);
|
||||
if(p != pct) {
|
||||
pct = p;
|
||||
Serial.printf("LEN:%d TOTAL:%d %d%%\n", len, total, pct);
|
||||
this->emitDownloadProgress(len, total);
|
||||
else {
|
||||
Serial.println("Update.end Called...");
|
||||
}
|
||||
delay(1);
|
||||
if(total >= len) {
|
||||
if(!Update.end(true)) {
|
||||
Serial.println("Error downloading update...");
|
||||
Update.printError(Serial);
|
||||
}
|
||||
else {
|
||||
Serial.println("Update.end Called...");
|
||||
}
|
||||
https.end();
|
||||
}
|
||||
}
|
||||
else {
|
||||
timeouts++;
|
||||
if(timeouts >= 500) {
|
||||
Update.abort();
|
||||
https.end();
|
||||
free(buff);
|
||||
Serial.println("Stream timeout!!!");
|
||||
return -43;
|
||||
}
|
||||
sockEmit.loop();
|
||||
webServer.loop();
|
||||
delay(100);
|
||||
https.end();
|
||||
sclient.stop();
|
||||
}
|
||||
}
|
||||
free(buff);
|
||||
if(len > total) {
|
||||
Update.abort();
|
||||
somfy.commit();
|
||||
Serial.println("Error downloading file!!!");
|
||||
return -42;
|
||||
|
||||
else {
|
||||
timeouts++;
|
||||
if(timeouts >= 500) {
|
||||
Update.abort();
|
||||
https.end();
|
||||
free(buff);
|
||||
Serial.println("Stream timeout!!!");
|
||||
return -43;
|
||||
}
|
||||
sockEmit.loop();
|
||||
webServer.loop();
|
||||
delay(100);
|
||||
}
|
||||
else
|
||||
Serial.printf("Update %s complete\n", this->currentFile);
|
||||
|
||||
}
|
||||
else {
|
||||
// TODO: memory allocation error.
|
||||
Serial.println("Unable to allocate memory for update!!!");
|
||||
free(buff);
|
||||
if(len > total) {
|
||||
Update.abort();
|
||||
somfy.commit();
|
||||
Serial.println("Error downloading file!!!");
|
||||
return -42;
|
||||
}
|
||||
else
|
||||
Serial.printf("Update %s complete\n", this->currentFile);
|
||||
}
|
||||
else {
|
||||
Serial.printf("Invalid HTTP Code... %d", httpCode);
|
||||
return httpCode;
|
||||
// TODO: memory allocation error.
|
||||
Serial.println("Unable to allocate memory for update!!!");
|
||||
}
|
||||
}
|
||||
else {
|
||||
Serial.printf("Invalid HTTP Code: %d\n", httpCode);
|
||||
}
|
||||
|
||||
if(https.connected()) https.end();
|
||||
Serial.printf("End update %s\n", this->currentFile);
|
||||
|
||||
else {
|
||||
Serial.printf("Invalid HTTP Code... %d", httpCode);
|
||||
return httpCode;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Serial.printf("Invalid HTTP Code: %d\n", httpCode);
|
||||
}
|
||||
client->stop();
|
||||
delete client;
|
||||
https.end();
|
||||
sclient.stop();
|
||||
Serial.printf("End update %s\n", this->currentFile);
|
||||
}
|
||||
esp_task_wdt_reset();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
8
GitOTA.h
8
GitOTA.h
|
|
@ -4,6 +4,7 @@
|
|||
#include <ArduinoJson.h>
|
||||
#include <time.h>
|
||||
#include "ConfigSettings.h"
|
||||
#include "WResp.h"
|
||||
|
||||
#define GIT_MAX_RELEASES 5
|
||||
#define GIT_STATUS_READY 0
|
||||
|
|
@ -27,14 +28,13 @@ class GitRelease {
|
|||
appver_t version;
|
||||
void setReleaseProperty(const char *key, const char *val);
|
||||
void setAssetProperty(const char *key, const char *val);
|
||||
bool toJSON(JsonObject &obj);
|
||||
|
||||
void toJSON(JsonResponse &json);
|
||||
};
|
||||
class GitRepo {
|
||||
public:
|
||||
int16_t getReleases(uint8_t num = GIT_MAX_RELEASES);
|
||||
GitRelease releases[GIT_MAX_RELEASES + 1];
|
||||
bool toJSON(JsonObject &obj);
|
||||
void toJSON(JsonResponse &json);
|
||||
};
|
||||
class GitUpdater {
|
||||
public:
|
||||
|
|
@ -58,7 +58,7 @@ class GitUpdater {
|
|||
void setFirmwareFile();
|
||||
void setCurrentRelease(GitRepo &repo);
|
||||
void loop();
|
||||
void toJSON(JsonObject &obj);
|
||||
void toJSON(JsonResponse &json);
|
||||
bool recoverFilesystem();
|
||||
int checkInternet();
|
||||
void emitUpdateCheck(uint8_t num=255);
|
||||
|
|
|
|||
33
MQTT.cpp
33
MQTT.cpp
|
|
@ -1,8 +1,9 @@
|
|||
#include <WiFi.h>
|
||||
#include <PubSubClient.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include "MQTT.h"
|
||||
#include <esp_task_wdt.h>
|
||||
#include "ConfigSettings.h"
|
||||
#include "MQTT.h"
|
||||
#include "Somfy.h"
|
||||
#include "Network.h"
|
||||
#include "Utils.h"
|
||||
|
|
@ -34,12 +35,16 @@ void MQTTClass::reset() {
|
|||
this->connect();
|
||||
}
|
||||
bool MQTTClass::loop() {
|
||||
if(settings.MQTT.enabled && !rebootDelay.reboot && !this->suspended && !mqttClient.connected())
|
||||
this->connect();
|
||||
if(settings.MQTT.enabled && !rebootDelay.reboot && !this->suspended && !mqttClient.connected()) {
|
||||
esp_task_wdt_reset();
|
||||
if(!this->connected() && net.connected()) this->connect();
|
||||
}
|
||||
esp_task_wdt_reset();
|
||||
if(settings.MQTT.enabled) mqttClient.loop();
|
||||
return true;
|
||||
}
|
||||
void MQTTClass::receive(const char *topic, byte*payload, uint32_t length) {
|
||||
esp_task_wdt_reset(); // Make sure we do not reboot here.
|
||||
Serial.print("MQTT Topic:");
|
||||
Serial.print(topic);
|
||||
Serial.print(" payload:");
|
||||
|
|
@ -178,8 +183,10 @@ void MQTTClass::receive(const char *topic, byte*payload, uint32_t length) {
|
|||
}
|
||||
}
|
||||
}
|
||||
esp_task_wdt_reset(); // Make sure we do not reboot here.
|
||||
}
|
||||
bool MQTTClass::connect() {
|
||||
esp_task_wdt_reset(); // Make sure we do not reboot here.
|
||||
if(mqttClient.connected()) {
|
||||
if(!settings.MQTT.enabled || this->suspended)
|
||||
return this->disconnect();
|
||||
|
|
@ -195,6 +202,7 @@ bool MQTTClass::connect() {
|
|||
char lwtTopic[128] = "status";
|
||||
if(strlen(settings.MQTT.rootTopic) > 0)
|
||||
snprintf(lwtTopic, sizeof(lwtTopic), "%s/status", settings.MQTT.rootTopic);
|
||||
esp_task_wdt_reset();
|
||||
if(mqttClient.connect(this->clientId, settings.MQTT.username, settings.MQTT.password, lwtTopic, 0, true, "offline")) {
|
||||
Serial.print("Successfully connected MQTT client ");
|
||||
Serial.println(this->clientId);
|
||||
|
|
@ -219,8 +227,9 @@ bool MQTTClass::connect() {
|
|||
this->subscribe("groups/+/sunFlag/set");
|
||||
this->subscribe("groups/+/sunny/set");
|
||||
this->subscribe("groups/+/windy/set");
|
||||
|
||||
mqttClient.setCallback(MQTTClass::receive);
|
||||
Serial.println("MQTT Startup Completed");
|
||||
esp_task_wdt_reset();
|
||||
this->lastConnect = millis();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -272,6 +281,7 @@ bool MQTTClass::unsubscribe(const char *topic) {
|
|||
}
|
||||
bool MQTTClass::subscribe(const char *topic) {
|
||||
if(mqttClient.connected()) {
|
||||
esp_task_wdt_reset(); // Make sure we do not reboot here.
|
||||
char top[128];
|
||||
if(strlen(settings.MQTT.rootTopic) > 0)
|
||||
snprintf(top, sizeof(top), "%s/%s", settings.MQTT.rootTopic, topic);
|
||||
|
|
@ -290,6 +300,7 @@ bool MQTTClass::publish(const char *topic, const char *payload, bool retain) {
|
|||
snprintf(top, sizeof(top), "%s/%s", settings.MQTT.rootTopic, topic);
|
||||
else
|
||||
strlcpy(top, topic, sizeof(top));
|
||||
esp_task_wdt_reset(); // Make sure we do not reboot here.
|
||||
mqttClient.publish(top, payload, retain);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -299,18 +310,6 @@ bool MQTTClass::publish(const char *topic, uint32_t val, bool retain) {
|
|||
snprintf(g_content, sizeof(g_content), "%u", val);
|
||||
return this->publish(topic, g_content, retain);
|
||||
}
|
||||
bool MQTTClass::publish(const char *topic, JsonDocument &doc, bool retain) {
|
||||
serializeJson(doc, g_content, sizeof(g_content));
|
||||
return this->publish(topic, g_content, retain);
|
||||
}
|
||||
bool MQTTClass::publish(const char *topic, JsonArray &arr, bool retain) {
|
||||
serializeJson(arr, g_content, sizeof(g_content));
|
||||
return this->publish(topic, g_content, retain);
|
||||
}
|
||||
bool MQTTClass::publish(const char *topic, JsonObject &obj, bool retain) {
|
||||
serializeJson(obj, g_content, sizeof(g_content));
|
||||
return this->publish(topic, g_content, retain);
|
||||
}
|
||||
bool MQTTClass::unpublish(const char *topic) {
|
||||
if(mqttClient.connected()) {
|
||||
char top[128];
|
||||
|
|
@ -318,6 +317,7 @@ bool MQTTClass::unpublish(const char *topic) {
|
|||
snprintf(top, sizeof(top), "%s/%s", settings.MQTT.rootTopic, topic);
|
||||
else
|
||||
strlcpy(top, topic, sizeof(top));
|
||||
esp_task_wdt_reset(); // Make sure we do not reboot here.
|
||||
mqttClient.publish(top, (const uint8_t *)"", 0, true);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -332,6 +332,7 @@ bool MQTTClass::publishBuffer(const char *topic, uint8_t *data, uint16_t len, bo
|
|||
uint16_t offset = 0;
|
||||
uint16_t to_write = len;
|
||||
uint16_t buff_len;
|
||||
esp_task_wdt_reset(); // Make sure we do not reboot here.
|
||||
mqttClient.beginPublish(topic, len, retain);
|
||||
do {
|
||||
buff_len = to_write;
|
||||
|
|
|
|||
3
MQTT.h
3
MQTT.h
|
|
@ -17,9 +17,6 @@ class MQTTClass {
|
|||
void reset();
|
||||
bool unpublish(const char *topic);
|
||||
bool publish(const char *topic, const char *payload, bool retain = false);
|
||||
bool publish(const char *topic, JsonDocument &doc, bool retain = false);
|
||||
bool publish(const char *topic, JsonArray &arr, bool retain = false);
|
||||
bool publish(const char *topic, JsonObject &obj, bool retain = false);
|
||||
bool publish(const char *topic, uint8_t val, bool retain = false);
|
||||
bool publish(const char *topic, int8_t val, bool retain = false);
|
||||
bool publish(const char *topic, uint32_t val, bool retain = false);
|
||||
|
|
|
|||
763
Network.cpp
763
Network.cpp
|
|
@ -1,6 +1,7 @@
|
|||
#include <ETH.h>
|
||||
#include <WiFi.h>
|
||||
#include <ESPmDNS.h>
|
||||
#include <esp_task_wdt.h>
|
||||
#include "ConfigSettings.h"
|
||||
#include "Network.h"
|
||||
#include "Web.h"
|
||||
|
|
@ -15,201 +16,245 @@ extern SocketEmitter sockEmit;
|
|||
extern MQTTClass mqtt;
|
||||
extern rebootDelay_t rebootDelay;
|
||||
extern Network net;
|
||||
extern SomfyShadeController somfy;
|
||||
|
||||
static unsigned long _lastHeapEmit = 0;
|
||||
|
||||
static bool _apScanning = false;
|
||||
static uint32_t _lastMaxHeap = 0;
|
||||
static uint32_t _lastHeap = 0;
|
||||
int connectRetries = 0;
|
||||
void Network::end() {
|
||||
sockEmit.end();
|
||||
SSDP.end();
|
||||
mqtt.end();
|
||||
sockEmit.end();
|
||||
delay(100);
|
||||
}
|
||||
bool Network::setup() {
|
||||
WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN);
|
||||
WiFi.setSortMethod(WIFI_CONNECT_AP_BY_SIGNAL);
|
||||
WiFi.persistent(false);
|
||||
WiFi.setAutoReconnect(false);
|
||||
WiFi.onEvent(this->networkEvent);
|
||||
this->disconnectTime = millis();
|
||||
if(WiFi.status() == WL_CONNECTED) WiFi.disconnect(true, true);
|
||||
if(settings.connType == conn_types::wifi || settings.connType == conn_types::unset) {
|
||||
if(settings.connType == conn_types_t::wifi || settings.connType == conn_types_t::unset) {
|
||||
WiFi.persistent(false);
|
||||
if(settings.hostname[0] != '\0') WiFi.setHostname(settings.hostname);
|
||||
Serial.print("WiFi Mode: ");
|
||||
Serial.println(WiFi.getMode());
|
||||
WiFi.mode(WIFI_STA);
|
||||
settings.WIFI.printNetworks();
|
||||
}
|
||||
sockEmit.begin();
|
||||
if(!this->connect()) this->openSoftAP();
|
||||
return true;
|
||||
}
|
||||
conn_types_t Network::preferredConnType() {
|
||||
switch(settings.connType) {
|
||||
case conn_types_t::wifi:
|
||||
return settings.WIFI.ssid[0] != '\0' ? conn_types_t::wifi : conn_types_t::ap;
|
||||
case conn_types_t::unset:
|
||||
case conn_types_t::ap:
|
||||
return conn_types_t::ap;
|
||||
case conn_types_t::ethernetpref:
|
||||
return settings.WIFI.ssid[0] != '\0' && (!ETH.linkUp() && this->ethStarted) ? conn_types_t::wifi : conn_types_t::ethernet;
|
||||
case conn_types_t::ethernet:
|
||||
return ETH.linkUp() || !this->ethStarted ? conn_types_t::ethernet : conn_types_t::ap;
|
||||
default:
|
||||
return settings.connType;
|
||||
}
|
||||
}
|
||||
void Network::loop() {
|
||||
if(millis() - this->lastEmit > 1500) {
|
||||
this->lastEmit = millis();
|
||||
if(!this->softAPOpened) {
|
||||
while(!this->connect()) {
|
||||
// If we lost our connection
|
||||
connectRetries++;
|
||||
if(connectRetries > 100) {
|
||||
if(!this->connected()) this->openSoftAP();
|
||||
break;
|
||||
}
|
||||
sockEmit.loop();
|
||||
}
|
||||
connectRetries = 0;
|
||||
}
|
||||
this->emitSockets();
|
||||
this->lastEmit = millis();
|
||||
if(!this->connected()) return;
|
||||
}
|
||||
if(this->connected() && millis() - this->lastMDNS > 60000) {
|
||||
// We are doing this every 60 seconds because of the BS related to
|
||||
// the MDNS library. The original library required manual updates
|
||||
// to the MDNS or it would lose its hostname after 2 minutes.
|
||||
if(this->lastMDNS != 0) MDNS.setInstanceName(settings.hostname);
|
||||
// Every 60 seconds we are going to look at wifi connectivity
|
||||
// to get around the roaming issues with ESP32. We will try to do this in an async manner. If
|
||||
// there is a channel that is better we will stop the radio and reconnect
|
||||
if(this->connType == conn_types::wifi && settings.WIFI.roaming && !this->softAPOpened) {
|
||||
// If we are not already scanning then we need to start a passive scan
|
||||
// and only respond if there is a better connection.
|
||||
// 1. If there is currently a waiting scan don't do anything
|
||||
if(!_apScanning && WiFi.scanNetworks(true, false, true, 300, 0, settings.WIFI.ssid) == -1) {
|
||||
_apScanning = true;
|
||||
}
|
||||
}
|
||||
this->lastMDNS = millis();
|
||||
}
|
||||
// ORDER OF OPERATIONS:
|
||||
// ----------------------------------------------
|
||||
// 1. If we are in the middle of a connection process we need to simply bail after the connect method. The
|
||||
// connect method will take care of our target connection for us.
|
||||
// 2. Check to see what type of target connection we need.
|
||||
// a. If this is an ethernet target then the connection needs to perform a fallback if applicable.
|
||||
// b. If this is a wifi target then we need to first check to see if the SSID is available.
|
||||
// c. If an SSID has not been set then we need to turn on the Soft AP.
|
||||
// 3. If the Soft AP is open and the target is either wifi, ethernet, or ethernetpref then
|
||||
// we need to shut it down if there are no connections and the preferred connection is available.
|
||||
// a. Ethernet: Check for an active ethernet connection. We cannot rely on linkup because the PHY will
|
||||
// report that the link is up when no IP address is being served.
|
||||
// b. WiFi: Perform synchronous scan for APs related to the SSID. If the SSID can be found then perform
|
||||
// the connection process for the WiFi connection.
|
||||
// c. SoftAP: This condition retains the Soft AP because no other connection method is available.
|
||||
conn_types_t ctype = this->preferredConnType();
|
||||
this->connect(ctype); // Connection timeout handled in connect function as well as the opening of the Soft AP if needed.
|
||||
if(this->connecting()) return; // If we are currently attempting to connect to something then we need to bail here.
|
||||
if(_apScanning) {
|
||||
if(!settings.WIFI.roaming || this->connType != conn_types::wifi || this->softAPOpened) _apScanning = false;
|
||||
if(settings.WIFI.hidden || // This user has elected to use a hidden AP.
|
||||
(this->connected() && !settings.WIFI.roaming) || // We are already connected and should not be roaming.
|
||||
(this->softAPOpened && WiFi.softAPgetStationNum() != 0) || // The Soft AP is open and a user is connected.
|
||||
(ctype != conn_types_t::wifi)) { // The Ethernet link is up so we should ignore this scan.
|
||||
Serial.println("Cancelling WiFi STA Scan...");
|
||||
_apScanning = false;
|
||||
WiFi.scanDelete();
|
||||
}
|
||||
else {
|
||||
uint16_t n = WiFi.scanComplete();
|
||||
if( n > 0) {
|
||||
_apScanning = false;
|
||||
int16_t n = WiFi.scanComplete();
|
||||
if( n >= 0) { // If the scan is complete but the WiFi isn't ready this can return 0.
|
||||
uint8_t bssid[6];
|
||||
int32_t channel = 0;
|
||||
if(this->getStrongestAP(settings.WIFI.ssid, bssid, &channel)) {
|
||||
if(memcmp(bssid, WiFi.BSSID(), sizeof(bssid)) != 0) {
|
||||
Serial.printf("Found stronger AP %d %02X:%02X:%02X:%02X:%02X:%02X\n", channel, bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
|
||||
this->changeAP(bssid, channel);
|
||||
if(!WiFi.BSSID() || memcmp(bssid, WiFi.BSSID(), sizeof(bssid)) != 0) {
|
||||
if(!this->connected()) {
|
||||
Serial.printf("Connecting to AP %02X:%02X:%02X:%02X:%02X:%02X CH: %d\n", bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5], channel);
|
||||
this->connectWiFi(bssid, channel);
|
||||
}
|
||||
else {
|
||||
Serial.printf("Found stronger AP %02X:%02X:%02X:%02X:%02X:%02X CH: %d\n", bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5], channel);
|
||||
this->changeAP(bssid, channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
_apScanning = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!this->connecting() && !settings.WIFI.hidden) {
|
||||
if((this->softAPOpened && WiFi.softAPgetStationNum() == 0) ||
|
||||
(!this->connected() && ctype == conn_types_t::wifi)) {
|
||||
// If the Soft AP is opened and there are no clients connected then we need to scan for an AP. If
|
||||
// our target exists we will exit out of the Soft AP and start that connection. We are also
|
||||
// going to continuously scan when there is no connection and our preferred connection is wifi.
|
||||
if(ctype == conn_types_t::wifi) {
|
||||
// Scan for an AP but only if we are not already scanning.
|
||||
if(!_apScanning && WiFi.scanNetworks(true, false, true, 300, 0, settings.WIFI.ssid) == -1) {
|
||||
_apScanning = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(this->connected() && ctype == conn_types_t::wifi && settings.WIFI.roaming) {
|
||||
// Periodically look for a roaming AP.
|
||||
if(millis() > SSID_SCAN_INTERVAL + this->lastWifiScan) {
|
||||
//Serial.println("Started scan for access points");
|
||||
if(!_apScanning && WiFi.scanNetworks(true, false, true, 300, 0, settings.WIFI.ssid) == -1) {
|
||||
_apScanning = true;
|
||||
this->lastWifiScan = millis();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(settings.ssdpBroadcast) {
|
||||
if(millis() - this->lastEmit > 1500) {
|
||||
// Post our connection status if needed.
|
||||
this->lastEmit = millis();
|
||||
if(this->connected()) {
|
||||
this->emitSockets();
|
||||
this->lastEmit = millis();
|
||||
}
|
||||
esp_task_wdt_reset(); // Make sure we do not reboot here.
|
||||
}
|
||||
|
||||
sockEmit.loop();
|
||||
mqtt.loop();
|
||||
if(settings.ssdpBroadcast && this->connected()) {
|
||||
if(!SSDP.isStarted) SSDP.begin();
|
||||
if(SSDP.isStarted) SSDP.loop();
|
||||
}
|
||||
else if(!settings.ssdpBroadcast && SSDP.isStarted) SSDP.end();
|
||||
mqtt.loop();
|
||||
}
|
||||
bool Network::changeAP(const uint8_t *bssid, const int32_t channel) {
|
||||
esp_task_wdt_reset(); // Make sure we do not reboot here.
|
||||
if(SSDP.isStarted) SSDP.end();
|
||||
mqtt.disconnect();
|
||||
//sockEmit.end();
|
||||
WiFi.disconnect(false, true);
|
||||
this->connType = conn_types_t::unset;
|
||||
this->_connecting = true;
|
||||
this->connectStart = millis();
|
||||
WiFi.begin(settings.WIFI.ssid, settings.WIFI.passphrase, channel, bssid);
|
||||
uint8_t retries = 0;
|
||||
while(retries < 100) {
|
||||
wl_status_t stat = WiFi.status();
|
||||
if(stat == WL_CONNECTED) {
|
||||
Serial.println("WiFi module connected");
|
||||
this->ssid = WiFi.SSID();
|
||||
this->mac = WiFi.BSSIDstr();
|
||||
this->strength = WiFi.RSSI();
|
||||
this->channel = WiFi.channel();
|
||||
return true;
|
||||
}
|
||||
else if(stat == WL_CONNECT_FAILED) {
|
||||
Serial.println("WiFi Module connection failed");
|
||||
return false;
|
||||
}
|
||||
else if(stat == WL_NO_SSID_AVAIL) {
|
||||
Serial.println(" Connection failed the SSID ");
|
||||
return false;
|
||||
}
|
||||
else if(stat == WL_NO_SHIELD) {
|
||||
Serial.println("Connection failed - WiFi module not found");
|
||||
return false;
|
||||
}
|
||||
else if(stat == WL_IDLE_STATUS) {
|
||||
Serial.print("*");
|
||||
}
|
||||
else if(stat == WL_DISCONNECTED) {
|
||||
Serial.print("-");
|
||||
}
|
||||
else {
|
||||
Serial.printf("Unknown status %d\n", stat);
|
||||
}
|
||||
delay(300);
|
||||
}
|
||||
this->connectStart = millis();
|
||||
return false;
|
||||
}
|
||||
void Network::emitSockets() {
|
||||
this->emitHeap();
|
||||
if(this->needsBroadcast ||
|
||||
(this->connType == conn_types::wifi && (abs(abs(WiFi.RSSI()) - abs(this->lastRSSI)) > 1 || WiFi.channel() != this->lastChannel))) {
|
||||
(this->connType == conn_types_t::wifi && (abs(abs(WiFi.RSSI()) - abs(this->lastRSSI)) > 1 || WiFi.channel() != this->lastChannel))) {
|
||||
this->emitSockets(255);
|
||||
sockEmit.loop();
|
||||
this->needsBroadcast = false;
|
||||
}
|
||||
}
|
||||
void Network::emitSockets(uint8_t num) {
|
||||
char buf[128];
|
||||
if(this->connType == conn_types::ethernet) {
|
||||
snprintf(buf, sizeof(buf), "{\"connected\":%s,\"speed\":%d,\"fullduplex\":%s}", this->connected() ? "true" : "false", ETH.linkSpeed(), ETH.fullDuplex() ? "true" : "false");
|
||||
if(num == 255)
|
||||
sockEmit.sendToClients("ethernet", buf);
|
||||
else
|
||||
sockEmit.sendToClient(num, "ethernet", buf);
|
||||
if(this->connType == conn_types_t::ethernet) {
|
||||
JsonSockEvent *json = sockEmit.beginEmit("ethernet");
|
||||
json->beginObject();
|
||||
json->addElem("connected", this->connected());
|
||||
json->addElem("speed", ETH.linkSpeed());
|
||||
json->addElem("fullduplex", ETH.fullDuplex());
|
||||
json->endObject();
|
||||
sockEmit.endEmit(num);
|
||||
}
|
||||
else {
|
||||
if(WiFi.status() == WL_CONNECTED) {
|
||||
snprintf(buf, sizeof(buf), "{\"ssid\":\"%s\",\"strength\":%d,\"channel\":%d}", WiFi.SSID().c_str(), WiFi.RSSI(), this->channel);
|
||||
if(num == 255)
|
||||
sockEmit.sendToClients("wifiStrength", buf);
|
||||
else
|
||||
sockEmit.sendToClient(num, "wifiStrength", buf);
|
||||
JsonSockEvent *json = sockEmit.beginEmit("wifiStrength");
|
||||
json->beginObject();
|
||||
json->addElem("ssid", WiFi.SSID().c_str());
|
||||
json->addElem("strength", (int32_t)WiFi.RSSI());
|
||||
json->addElem("channel", (int32_t)this->channel);
|
||||
json->endObject();
|
||||
sockEmit.endEmit(num);
|
||||
this->lastRSSI = WiFi.RSSI();
|
||||
this->lastChannel = WiFi.channel();
|
||||
}
|
||||
else {
|
||||
if(num == 255) {
|
||||
sockEmit.sendToClients("wifiStrength", "{\"ssid\":\"\", \"strength\":-100,\"channel\":-1}");
|
||||
sockEmit.sendToClients("ethernet", "{\"connected\":false,\"speed\":0,\"fullduplex\":false}");
|
||||
}
|
||||
else {
|
||||
sockEmit.sendToClient(num, "wifiStrength", "{\"ssid\":\"\", \"strength\":-100,\"channel\":-1}");
|
||||
sockEmit.sendToClient(num, "ethernet", "{\"connected\":false,\"speed\":0,\"fullduplex\":false}");
|
||||
}
|
||||
JsonSockEvent *json = sockEmit.beginEmit("wifiStrength");
|
||||
json->beginObject();
|
||||
json->addElem("ssid", "");
|
||||
json->addElem("strength", (int8_t)-100);
|
||||
json->addElem("channel", (int8_t)-1);
|
||||
json->endObject();
|
||||
sockEmit.endEmit(num);
|
||||
|
||||
json = sockEmit.beginEmit("ethernet");
|
||||
json->beginObject();
|
||||
json->addElem("connected", false);
|
||||
json->addElem("speed", (uint8_t)0);
|
||||
json->addElem("fullduplex", false);
|
||||
json->endObject();
|
||||
sockEmit.endEmit(num);
|
||||
this->lastRSSI = -100;
|
||||
this->lastChannel = -1;
|
||||
}
|
||||
}
|
||||
this->emitHeap(num);
|
||||
}
|
||||
void Network::setConnected(conn_types connType) {
|
||||
void Network::setConnected(conn_types_t connType) {
|
||||
esp_task_wdt_reset();
|
||||
this->connType = connType;
|
||||
this->connectTime = millis();
|
||||
connectRetries = 0;
|
||||
if(this->connType == conn_types::wifi) {
|
||||
if(this->softAPOpened) {
|
||||
Serial.println("Setting connected...");
|
||||
if(this->connType == conn_types_t::wifi) {
|
||||
if(this->softAPOpened && WiFi.softAPgetStationNum() == 0) {
|
||||
WiFi.softAPdisconnect(true);
|
||||
WiFi.mode(WIFI_STA);
|
||||
}
|
||||
this->_connecting = false;
|
||||
this->ssid = WiFi.SSID();
|
||||
this->mac = WiFi.BSSIDstr();
|
||||
this->strength = WiFi.RSSI();
|
||||
this->channel = WiFi.channel();
|
||||
this->connectAttempts++;
|
||||
}
|
||||
else if(this->connType == conn_types::ethernet) {
|
||||
else if(this->connType == conn_types_t::ethernet) {
|
||||
if(this->softAPOpened) {
|
||||
Serial.println("Disonnecting from SoftAP");
|
||||
WiFi.softAPdisconnect(true);
|
||||
WiFi.mode(WIFI_OFF);
|
||||
}
|
||||
this->connectAttempts++;
|
||||
this->_connecting = false;
|
||||
this->wifiFallback = false;
|
||||
}
|
||||
// NET: Begin this in the startup.
|
||||
//sockEmit.begin();
|
||||
esp_task_wdt_reset();
|
||||
|
||||
if(this->connectAttempts == 1) {
|
||||
Serial.println();
|
||||
if(this->connType == conn_types::wifi) {
|
||||
if(this->connType == conn_types_t::wifi) {
|
||||
Serial.print("Successfully Connected to WiFi!!!!");
|
||||
Serial.print(WiFi.localIP());
|
||||
Serial.print(" (");
|
||||
|
|
@ -239,9 +284,15 @@ void Network::setConnected(conn_types connType) {
|
|||
settings.IP.dns1 = ETH.dnsIP(0);
|
||||
settings.IP.dns2 = ETH.dnsIP(1);
|
||||
}
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof(buf), "{\"connected\":true,\"speed\":%d,\"fullduplex\":%s}", ETH.linkSpeed(), ETH.fullDuplex() ? "true" : "false");
|
||||
sockEmit.sendToClients("ethernet", buf);
|
||||
esp_task_wdt_reset();
|
||||
JsonSockEvent *json = sockEmit.beginEmit("ethernet");
|
||||
json->beginObject();
|
||||
json->addElem("connected", this->connected());
|
||||
json->addElem("speed", ETH.linkSpeed());
|
||||
json->addElem("fullduplex", ETH.fullDuplex());
|
||||
json->endObject();
|
||||
sockEmit.endEmit();
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
@ -249,7 +300,7 @@ void Network::setConnected(conn_types connType) {
|
|||
Serial.print("Reconnected after ");
|
||||
Serial.print(1.0 * (millis() - this->connectStart)/1000);
|
||||
Serial.print("sec IP: ");
|
||||
if(this->connType == conn_types::wifi) {
|
||||
if(this->connType == conn_types_t::wifi) {
|
||||
Serial.print(WiFi.localIP());
|
||||
Serial.print(" ");
|
||||
Serial.print(this->mac);
|
||||
|
|
@ -284,7 +335,7 @@ void Network::setConnected(conn_types connType) {
|
|||
if(strlen(settings.chipModel) == 0) SSDP.setModelNumber(0, "ESP32");
|
||||
else {
|
||||
char sModel[20] = "";
|
||||
snprintf(sModel, sizeof(sModel), "ESP32-%S", settings.chipModel);
|
||||
snprintf(sModel, sizeof(sModel), "ESP32-%s", settings.chipModel);
|
||||
SSDP.setModelNumber(0, sModel);
|
||||
}
|
||||
SSDP.setModelURL(0, "https://github.com/rstrouse/ESPSomfy-RTS");
|
||||
|
|
@ -292,9 +343,10 @@ void Network::setConnected(conn_types connType) {
|
|||
SSDP.setManufacturerURL(0, "https://github.com/rstrouse");
|
||||
SSDP.setURL(0, "/");
|
||||
SSDP.setActive(0, true);
|
||||
esp_task_wdt_reset();
|
||||
if(MDNS.begin(settings.hostname)) {
|
||||
Serial.printf("MDNS Responder Started: serverId=%s\n", settings.serverId);
|
||||
//MDNS.addService("http", "tcp", 80);
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
//MDNS.addServiceTxt("http", "tcp", "board", "ESP32");
|
||||
//MDNS.addServiceTxt("http", "tcp", "model", "ESPSomfyRTS");
|
||||
|
||||
|
|
@ -304,26 +356,29 @@ void Network::setConnected(conn_types connType) {
|
|||
MDNS.addServiceTxt("espsomfy_rts", "tcp", "version", String(settings.fwVersion.name));
|
||||
}
|
||||
if(settings.ssdpBroadcast) {
|
||||
esp_task_wdt_reset();
|
||||
SSDP.begin();
|
||||
}
|
||||
else if(SSDP.isStarted) SSDP.end();
|
||||
esp_task_wdt_reset();
|
||||
this->emitSockets();
|
||||
settings.printAvailHeap();
|
||||
this->needsBroadcast = true;
|
||||
}
|
||||
bool Network::connectWired() {
|
||||
//if(this->connType == conn_types::ethernet && ETH.linkUp()) {
|
||||
if(ETH.linkUp()) {
|
||||
// If the ethernet link is re-established then we need to shut down wifi.
|
||||
if(WiFi.status() == WL_CONNECTED) {
|
||||
//sockEmit.end();
|
||||
WiFi.disconnect(true);
|
||||
WiFi.mode(WIFI_OFF);
|
||||
}
|
||||
if(this->connType != conn_types::ethernet) this->setConnected(conn_types::ethernet);
|
||||
this->wifiFallback = false;
|
||||
if(this->connType != conn_types_t::ethernet) this->setConnected(conn_types_t::ethernet);
|
||||
return true;
|
||||
}
|
||||
else if(this->ethStarted) {
|
||||
if(settings.connType == conn_types::ethernetpref && settings.WIFI.ssid[0] != '\0')
|
||||
// There is no wired connection so we need to fallback if appropriate.
|
||||
if(settings.connType == conn_types_t::ethernetpref && settings.WIFI.ssid[0] != '\0')
|
||||
return this->connectWiFi();
|
||||
}
|
||||
if(this->connectAttempts > 0) {
|
||||
|
|
@ -332,56 +387,45 @@ bool Network::connectWired() {
|
|||
}
|
||||
else
|
||||
Serial.println("Connecting to Wired Ethernet");
|
||||
this->connectAttempts++;
|
||||
this->_connecting = true;
|
||||
this->connTarget = conn_types_t::ethernet;
|
||||
this->connType = conn_types_t::unset;
|
||||
if(!this->ethStarted) {
|
||||
this->ethStarted = true;
|
||||
WiFi.mode(WIFI_OFF);
|
||||
if(settings.hostname[0] != '\0')
|
||||
ETH.setHostname(settings.hostname);
|
||||
// Currently the ethernet module will leak memory if you call begin more than once.
|
||||
this->ethStarted = true;
|
||||
WiFi.mode(WIFI_OFF);
|
||||
if(settings.hostname[0] != '\0')
|
||||
ETH.setHostname(settings.hostname);
|
||||
else
|
||||
ETH.setHostname("ESPSomfy-RTS");
|
||||
Serial.print("Set hostname to:");
|
||||
Serial.println(ETH.getHostname());
|
||||
if(!ETH.begin(settings.Ethernet.phyAddress, settings.Ethernet.PWRPin, settings.Ethernet.MDCPin, settings.Ethernet.MDIOPin, settings.Ethernet.phyType, settings.Ethernet.CLKMode)) {
|
||||
Serial.println("Ethernet Begin failed");
|
||||
this->ethStarted = false;
|
||||
if(settings.connType == conn_types_t::ethernetpref) {
|
||||
this->wifiFallback = true;
|
||||
return connectWiFi();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if(!settings.IP.dhcp) {
|
||||
if(!ETH.config(settings.IP.ip, settings.IP.gateway, settings.IP.subnet, settings.IP.dns1, settings.IP.dns2)) {
|
||||
Serial.println("Unable to configure static IP address....");
|
||||
ETH.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE);
|
||||
}
|
||||
}
|
||||
else
|
||||
ETH.setHostname("ESPSomfy-RTS");
|
||||
|
||||
Serial.print("Set hostname to:");
|
||||
Serial.println(ETH.getHostname());
|
||||
if(!ETH.begin(settings.Ethernet.phyAddress, settings.Ethernet.PWRPin, settings.Ethernet.MDCPin, settings.Ethernet.MDIOPin, settings.Ethernet.phyType, settings.Ethernet.CLKMode)) {
|
||||
Serial.println("Ethernet Begin failed");
|
||||
this->ethStarted = false;
|
||||
if(settings.connType == conn_types::ethernetpref) {
|
||||
this->wifiFallback = true;
|
||||
return connectWiFi();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if(!settings.IP.dhcp) {
|
||||
if(!ETH.config(settings.IP.ip, settings.IP.gateway, settings.IP.subnet, settings.IP.dns1, settings.IP.dns2)) {
|
||||
Serial.println("Unable to configure static IP address....");
|
||||
ETH.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE);
|
||||
}
|
||||
}
|
||||
else
|
||||
ETH.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE);
|
||||
|
||||
uint32_t wait = millis();
|
||||
while(millis() - wait < 14000) {
|
||||
if(ETH.linkUp()) {
|
||||
net.mac = ETH.macAddress();
|
||||
net.setConnected(conn_types::ethernet);
|
||||
return true;
|
||||
}
|
||||
delay(500);
|
||||
}
|
||||
if(settings.connType == conn_types::ethernetpref) {
|
||||
this->wifiFallback = true;
|
||||
return connectWiFi();
|
||||
}
|
||||
}
|
||||
ETH.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
this->connectStart = millis();
|
||||
return true;
|
||||
}
|
||||
void Network::updateHostname() {
|
||||
if(settings.hostname[0] != '\0' && this->connected()) {
|
||||
if(this->connType == conn_types::ethernet &&
|
||||
if(this->connType == conn_types_t::ethernet &&
|
||||
strcmp(settings.hostname, ETH.getHostname()) != 0) {
|
||||
Serial.printf("Updating host name to %s...\n", settings.hostname);
|
||||
ETH.setHostname(settings.hostname);
|
||||
|
|
@ -396,12 +440,49 @@ void Network::updateHostname() {
|
|||
}
|
||||
}
|
||||
}
|
||||
bool Network::connectWiFi() {
|
||||
if(settings.WIFI.ssid[0] != '\0') {
|
||||
if(WiFi.status() == WL_CONNECTED && WiFi.SSID().compareTo(settings.WIFI.ssid) == 0) {
|
||||
bool Network::connectWiFi(const uint8_t *bssid, const int32_t channel) {
|
||||
if(this->softAPOpened && WiFi.softAPgetStationNum() > 0) {
|
||||
// There is a client connected to the soft AP. We do not want to close out the connection. While both the
|
||||
// Soft AP and a wifi connection can coexist on ESP32 the performance is abysmal.
|
||||
WiFi.disconnect(false);
|
||||
this->_connecting = false;
|
||||
this->connType = conn_types_t::unset;
|
||||
return true;
|
||||
}
|
||||
WiFi.setSleep(false);
|
||||
if(!settings.IP.dhcp) {
|
||||
if(!WiFi.config(settings.IP.ip, settings.IP.gateway, settings.IP.subnet, settings.IP.dns1, settings.IP.dns2))
|
||||
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE);
|
||||
}
|
||||
else
|
||||
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE);
|
||||
if(settings.hostname[0] != '\0') WiFi.setHostname(settings.hostname);
|
||||
delay(100);
|
||||
|
||||
if(bssid && channel > 0) {
|
||||
if(WiFi.status() == WL_CONNECTED && WiFi.SSID().compareTo(settings.WIFI.ssid) == 0
|
||||
&& WiFi.channel() == channel) {
|
||||
this->disconnected = 0;
|
||||
return true;
|
||||
}
|
||||
this->connTarget = conn_types_t::wifi;
|
||||
this->connType = conn_types_t::unset;
|
||||
Serial.println("WiFi begin...");
|
||||
this->_connecting = true;
|
||||
WiFi.begin(settings.WIFI.ssid, settings.WIFI.passphrase, channel, bssid);
|
||||
this->connectStart = millis();
|
||||
}
|
||||
else if(settings.WIFI.ssid[0] != '\0') {
|
||||
if(WiFi.status() == WL_CONNECTED && WiFi.SSID().compareTo(settings.WIFI.ssid) == 0) {
|
||||
// If we are connected to the target SSID then just return.
|
||||
this->disconnected = 0;
|
||||
this->_connecting = true;
|
||||
return true;
|
||||
}
|
||||
if(this->_connecting) return true;
|
||||
this->_connecting = true;
|
||||
this->connTarget = conn_types_t::wifi;
|
||||
this->connType = conn_types_t::unset;
|
||||
if(this->connectAttempts > 0) {
|
||||
Serial.print("Connection Lost...");
|
||||
Serial.print(this->mac);
|
||||
|
|
@ -412,108 +493,51 @@ bool Network::connectWiFi() {
|
|||
Serial.println("dbm) ");
|
||||
}
|
||||
else Serial.println("Connecting to AP");
|
||||
this->connectAttempts++;
|
||||
this->connectStart = millis();
|
||||
WiFi.setSleep(false);
|
||||
WiFi.mode(WIFI_MODE_NULL);
|
||||
//WiFi.onEvent(this->networkEvent);
|
||||
|
||||
if(!settings.IP.dhcp) {
|
||||
if(!WiFi.config(settings.IP.ip, settings.IP.gateway, settings.IP.subnet, settings.IP.dns1, settings.IP.dns2))
|
||||
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE);
|
||||
}
|
||||
else
|
||||
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE);
|
||||
delay(100);
|
||||
// There is also another method simply called hostname() but this is legacy for esp8266.
|
||||
if(settings.hostname[0] != '\0') WiFi.setHostname(settings.hostname);
|
||||
Serial.print("Set hostname to:");
|
||||
Serial.println(WiFi.getHostname());
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN);
|
||||
WiFi.setSortMethod(WIFI_CONNECT_AP_BY_SIGNAL);
|
||||
uint8_t bssid[6];
|
||||
int32_t channel = 0;
|
||||
if(this->getStrongestAP(settings.WIFI.ssid, bssid, &channel)) {
|
||||
Serial.printf("Found strongest AP %d %02X:%02X:%02X:%02X:%02X:%02X\n", channel, bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
|
||||
WiFi.begin(settings.WIFI.ssid, settings.WIFI.passphrase, channel, bssid);
|
||||
uint8_t _bssid[6];
|
||||
int32_t _channel = 0;
|
||||
if(!settings.WIFI.hidden && this->getStrongestAP(settings.WIFI.ssid, _bssid, &_channel)) {
|
||||
Serial.printf("Found strongest AP %02X:%02X:%02X:%02X:%02X:%02X CH:%d\n", _bssid[0], _bssid[1], _bssid[2], _bssid[3], _bssid[4], _bssid[5], _channel);
|
||||
WiFi.begin(settings.WIFI.ssid, settings.WIFI.passphrase, _channel, _bssid);
|
||||
}
|
||||
else
|
||||
// If the user has the hidden flag set just connect to whatever the AP gives us.
|
||||
WiFi.begin(settings.WIFI.ssid, settings.WIFI.passphrase);
|
||||
delay(100);
|
||||
int retries = 0;
|
||||
while(retries < 100) {
|
||||
switch(WiFi.status()) {
|
||||
case WL_SCAN_COMPLETED:
|
||||
Serial.println("Status: Scan Completed");
|
||||
break;
|
||||
case WL_CONNECT_FAILED:
|
||||
if(this->connectAttempts == 1) Serial.println();
|
||||
Serial.println("WiFi Module connection failed");
|
||||
return false;
|
||||
case WL_DISCONNECTED:
|
||||
break;
|
||||
case WL_IDLE_STATUS:
|
||||
Serial.print("*");
|
||||
break;
|
||||
case WL_CONNECTED:
|
||||
//WiFi.hostname(settings.hostname);
|
||||
this->ssid = WiFi.SSID();
|
||||
this->mac = WiFi.BSSIDstr();
|
||||
this->strength = WiFi.RSSI();
|
||||
this->channel = WiFi.channel();
|
||||
this->setConnected(conn_types::wifi);
|
||||
WiFi.setSleep(false);
|
||||
return true;
|
||||
case WL_NO_SHIELD:
|
||||
Serial.println("Connection failed - WiFi module not found");
|
||||
return false;
|
||||
case WL_NO_SSID_AVAIL:
|
||||
Serial.print(" Connection failed the SSID ");
|
||||
Serial.print(settings.WIFI.ssid);
|
||||
Serial.println(" could not be found");
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
delay(500);
|
||||
if(connectAttempts == 1) Serial.print("*");
|
||||
retries++;
|
||||
}
|
||||
this->connectStart = millis();
|
||||
return true;
|
||||
}
|
||||
bool Network::connect(conn_types_t ctype) {
|
||||
esp_task_wdt_reset();
|
||||
if(this->connecting()) return true;
|
||||
if(this->disconnectTime == 0) this->disconnectTime = millis();
|
||||
if(ctype == conn_types_t::ethernet && this->connType != conn_types_t::ethernet) {
|
||||
// Here we need to call the connect to ethernet.
|
||||
this->connectWired();
|
||||
}
|
||||
else if(ctype == conn_types_t::ap || (!this->connected() && millis() > this->disconnectTime + CONNECT_TIMEOUT)) {
|
||||
if(!this->softAPOpened && !this->openingSoftAP) {
|
||||
this->disconnectTime = millis();
|
||||
this->openSoftAP();
|
||||
}
|
||||
if(this->connectAttempts != 1) {
|
||||
int st = this->getStrengthBySSID(settings.WIFI.ssid);
|
||||
Serial.print("(");
|
||||
Serial.print(st);
|
||||
Serial.print("dBm) ");
|
||||
Serial.println("Failed");
|
||||
//if(disconnected > 0 && st == -100) settings.WIFI.PrintNetworks();
|
||||
disconnected++;
|
||||
else if(this->softAPOpened && !this->openingSoftAP &&
|
||||
(ctype == conn_types_t::wifi && this->connType != conn_types_t::wifi && settings.WIFI.hidden)) {
|
||||
// When thge softAP is open then we need to try to connect to wifi repeatedly if the user connects to a hidden SSID.
|
||||
this->connectWiFi();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool Network::connect() {
|
||||
if(settings.connType == conn_types::unset) return true;
|
||||
else if(settings.connType == conn_types::ethernet || (settings.connType == conn_types::ethernetpref)) {
|
||||
bool bConnected = this->connectWired();
|
||||
if(!bConnected && settings.connType == conn_types::ethernetpref && settings.WIFI.ssid[0] != '\0') {
|
||||
bConnected = this->connectWiFi();
|
||||
this->wifiFallback = true;
|
||||
}
|
||||
return bConnected;
|
||||
else if((ctype == conn_types_t::wifi && this->connType != conn_types_t::wifi && settings.WIFI.hidden)) {
|
||||
this->connectWiFi();
|
||||
}
|
||||
return this->connectWiFi();
|
||||
|
||||
return true;
|
||||
}
|
||||
/* DEPRECATED 03-02-24
|
||||
int Network::getStrengthByMac(const char *macAddr) {
|
||||
int n = WiFi.scanNetworks(true);
|
||||
for(int i = 0; i < n; i++) {
|
||||
if (WiFi.BSSIDstr(i).compareTo(macAddr) == 0)
|
||||
return WiFi.RSSI(i);
|
||||
}
|
||||
return -100;
|
||||
}
|
||||
*/
|
||||
uint32_t Network::getChipId() {
|
||||
uint32_t chipId = 0;
|
||||
uint64_t mac = ESP.getEfuseMac();
|
||||
|
|
@ -522,14 +546,16 @@ uint32_t Network::getChipId() {
|
|||
}
|
||||
return chipId;
|
||||
}
|
||||
|
||||
bool Network::getStrongestAP(const char *ssid, uint8_t *bssid, int32_t *channel) {
|
||||
// The new AP must be at least 10dbm greater.
|
||||
int32_t strength = this->connected() ? WiFi.RSSI() + 10 : -127;
|
||||
int32_t chan = -1;
|
||||
memset(bssid, 0x00, 6);
|
||||
uint8_t n = this->connected() ? WiFi.scanComplete() : WiFi.scanNetworks(false, false, false, 300, 0, ssid);
|
||||
for(uint8_t i = 0; i < n; i++) {
|
||||
esp_task_wdt_delete(NULL);
|
||||
int16_t n = WiFi.scanComplete();
|
||||
//int16_t n = this->connected() ? WiFi.scanComplete() : WiFi.scanNetworks(false, false, false, 300, 0, ssid);
|
||||
esp_task_wdt_add(NULL);
|
||||
for(int16_t i = 0; i < n; i++) {
|
||||
if(WiFi.SSID(i).compareTo(ssid) == 0) {
|
||||
if(WiFi.RSSI(i) > strength) {
|
||||
strength = WiFi.RSSI(i);
|
||||
|
|
@ -541,148 +567,145 @@ bool Network::getStrongestAP(const char *ssid, uint8_t *bssid, int32_t *channel)
|
|||
WiFi.scanDelete();
|
||||
return chan > 0;
|
||||
}
|
||||
int Network::getStrengthBySSID(const char *ssid) {
|
||||
int32_t strength = -100;
|
||||
int n = WiFi.scanNetworks(false, false);
|
||||
for(int i = 0; i < n; i++) {
|
||||
if(WiFi.SSID(i).compareTo(ssid) == 0) strength = max(WiFi.RSSI(i), strength);
|
||||
}
|
||||
if(strength == -100) {
|
||||
Serial.print("Could not find network [");
|
||||
Serial.print(ssid);
|
||||
Serial.print("] Scanned ");
|
||||
Serial.print(n);
|
||||
Serial.println(" Networks...");
|
||||
String network;
|
||||
for(int i = 0; i < n; i++) {
|
||||
//WiFi.getNetworkInfo(i, network, encType, RSSI, BSSID, channel, isHidden);
|
||||
if(network.compareTo(this->ssid) == 0) Serial.print("*");
|
||||
else Serial.print(" ");
|
||||
Serial.print(i);
|
||||
Serial.print(": ");
|
||||
Serial.print(WiFi.SSID(i).c_str());
|
||||
Serial.print(" (");
|
||||
Serial.print(WiFi.RSSI(i));
|
||||
Serial.print("dBm) CH:");
|
||||
Serial.print(WiFi.channel(i));
|
||||
Serial.print(" MAC:");
|
||||
Serial.print(WiFi.BSSIDstr(i).c_str());
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
return strength;
|
||||
}
|
||||
bool Network::openSoftAP() {
|
||||
if(this->softAPOpened || this->openingSoftAP) return true;
|
||||
if(this->connected()) WiFi.disconnect(false);
|
||||
this->openingSoftAP = true;
|
||||
Serial.println();
|
||||
Serial.println("Turning the HotSpot On");
|
||||
WiFi.disconnect(true);
|
||||
WiFi.hostname("ESPSomfy RTS");
|
||||
WiFi.mode(WIFI_AP_STA);
|
||||
delay(100);
|
||||
WiFi.softAP("ESPSomfy RTS", "");
|
||||
Serial.println("Initializing AP for credentials modification");
|
||||
Serial.println();
|
||||
Serial.print("SoftAP IP: ");
|
||||
Serial.println(WiFi.softAPIP());
|
||||
//pinMode(D0, INPUT_PULLUP);
|
||||
long startTime = millis();
|
||||
int c = 0;
|
||||
|
||||
while (!this->connected())
|
||||
{
|
||||
int clients = WiFi.softAPgetStationNum();
|
||||
webServer.loop();
|
||||
if(millis() - this->lastEmit > 1500) {
|
||||
//if(this->connect()) {}
|
||||
this->lastEmit = millis();
|
||||
this->emitSockets();
|
||||
if(clients > 0)
|
||||
Serial.print(clients);
|
||||
else
|
||||
Serial.print(".");
|
||||
c++;
|
||||
}
|
||||
sockEmit.loop();
|
||||
if(rebootDelay.reboot && millis() > rebootDelay.rebootTime) {
|
||||
this->end();
|
||||
ESP.restart();
|
||||
break;
|
||||
}
|
||||
|
||||
// If no clients have connected in 3 minutes from starting this server reboot this pig. This will
|
||||
// force a reboot cycle until we have some response. That is unless the SSID has been cleared.
|
||||
if(clients == 0 &&
|
||||
(strlen(settings.WIFI.ssid) > 0 || settings.connType == conn_types::ethernet || settings.connType == conn_types::ethernetpref) &&
|
||||
millis() - startTime > 3 * 60000) {
|
||||
Serial.println();
|
||||
Serial.println("Stopping AP Mode");
|
||||
WiFi.softAPdisconnect(true);
|
||||
return false;
|
||||
}
|
||||
if(c == 100) {
|
||||
Serial.println();
|
||||
c = 0;
|
||||
}
|
||||
yield();
|
||||
}
|
||||
esp_task_wdt_reset(); // Make sure we do not reboot here.
|
||||
WiFi.softAP(strlen(settings.hostname) > 0 ? settings.hostname : "ESPSomfy RTS", "");
|
||||
delay(200);
|
||||
return true;
|
||||
}
|
||||
bool Network::connected() {
|
||||
if(this->connType == conn_types::unset) return false;
|
||||
else if(this->connType == conn_types::wifi) return WiFi.status() == WL_CONNECTED;
|
||||
else if(this->connType == conn_types::ethernet) return ETH.linkUp();
|
||||
else return this->connType != conn_types::unset;
|
||||
if(this->connecting()) return false;
|
||||
else if(this->connType == conn_types_t::unset) return false;
|
||||
else if(this->connType == conn_types_t::wifi) return WiFi.status() == WL_CONNECTED;
|
||||
else if(this->connType == conn_types_t::ethernet) return ETH.linkUp();
|
||||
else return this->connType != conn_types_t::unset;
|
||||
return false;
|
||||
}
|
||||
bool Network::connecting() {
|
||||
if(this->_connecting && millis() > this->connectStart + CONNECT_TIMEOUT) this->_connecting = false;
|
||||
return this->_connecting;
|
||||
}
|
||||
void Network::clearConnecting() { this->_connecting = false; }
|
||||
void Network::networkEvent(WiFiEvent_t event) {
|
||||
switch(event) {
|
||||
case ARDUINO_EVENT_ETH_START:
|
||||
Serial.println("Ethernet Started");
|
||||
case ARDUINO_EVENT_WIFI_READY: Serial.println("(evt) WiFi interface ready"); break;
|
||||
case ARDUINO_EVENT_WIFI_SCAN_DONE:
|
||||
Serial.printf("(evt) Completed scan for access points (%d)\n", WiFi.scanComplete());
|
||||
//Serial.println("(evt) Completed scan for access points");
|
||||
net.lastWifiScan = millis();
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_START:
|
||||
Serial.println("WiFi station mode started");
|
||||
if(settings.hostname[0] != '\0') WiFi.setHostname(settings.hostname);
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_STOP: Serial.println("(evt) WiFi clients stopped"); break;
|
||||
case ARDUINO_EVENT_WIFI_STA_CONNECTED: Serial.println("(evt) Connected to WiFi STA access point"); break;
|
||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
||||
Serial.printf("(evt) Disconnected from WiFi STA access point. Connecting: %d\n", net.connecting());
|
||||
net.connType = conn_types_t::unset;
|
||||
net.disconnectTime = millis();
|
||||
net.clearConnecting();
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE: Serial.println("(evt) Authentication mode of STA access point has changed"); break;
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||
Serial.print("(evt) Got WiFi STA IP: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
net.connType = conn_types_t::wifi;
|
||||
net.connectTime = millis();
|
||||
net.setConnected(conn_types_t::wifi);
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_LOST_IP: Serial.println("Lost IP address and IP address is reset to 0"); break;
|
||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||
// If the Wifi is connected then drop that connection
|
||||
if(WiFi.status() == WL_CONNECTED) WiFi.disconnect(true);
|
||||
Serial.print("Got Ethernet IP ");
|
||||
Serial.println(ETH.localIP());
|
||||
net.connectTime = millis();
|
||||
net.connType = conn_types_t::ethernet;
|
||||
if(settings.IP.dhcp) {
|
||||
settings.IP.ip = ETH.localIP();
|
||||
settings.IP.subnet = ETH.subnetMask();
|
||||
settings.IP.gateway = ETH.gatewayIP();
|
||||
settings.IP.dns1 = ETH.dnsIP(0);
|
||||
settings.IP.dns2 = ETH.dnsIP(1);
|
||||
}
|
||||
net.setConnected(conn_types_t::ethernet);
|
||||
break;
|
||||
/*
|
||||
case ARDUINO_EVENT_ETH_LOST_IP:
|
||||
Serial.println("Ethernet Lost IP");
|
||||
sockEmit.sendToClients("ethernet", "{\"connected\":false, \"speed\":0,\"fullduplex\":false}");
|
||||
net.connType = conn_types::unset;
|
||||
break;
|
||||
*/
|
||||
case ARDUINO_EVENT_ETH_CONNECTED:
|
||||
Serial.print("Ethernet Connected ");
|
||||
// We don't want to call setConnected if we do not have an IP address yet
|
||||
//if(ETH.localIP() != INADDR_NONE)
|
||||
// net.setConnected(conn_types::ethernet);
|
||||
Serial.print("(evt) Ethernet Connected ");
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
||||
Serial.println("Ethernet Disconnected");
|
||||
sockEmit.sendToClients("ethernet", "{\"connected\":false,\"speed\":0,\"fullduplex\":false}");
|
||||
net.connType = conn_types::unset;
|
||||
Serial.println("(evt) Ethernet Disconnected");
|
||||
net.connType = conn_types_t::unset;
|
||||
net.disconnectTime = millis();
|
||||
net.clearConnecting();
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_START:
|
||||
Serial.println("(evt) Ethernet Started");
|
||||
net.ethStarted = true;
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_STOP:
|
||||
Serial.println("Ethernet Stopped");
|
||||
net.connType = conn_types::unset;
|
||||
Serial.println("(evt) Ethernet Stopped");
|
||||
net.connType = conn_types_t::unset;
|
||||
net.ethStarted = false;
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_AP_STOP:
|
||||
Serial.println("WiFi AP Stopped");
|
||||
net.softAPOpened = false;
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_AP_START:
|
||||
Serial.println("WiFi AP Started");
|
||||
Serial.print("(evt) WiFi SoftAP Started IP:");
|
||||
Serial.println(WiFi.softAPIP());
|
||||
net.openingSoftAP = false;
|
||||
net.softAPOpened = true;
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_START:
|
||||
if(settings.hostname[0] != '\0') WiFi.setHostname(settings.hostname);
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_AP_STOP:
|
||||
if(!net.openingSoftAP) Serial.println("(evt) WiFi SoftAP Stopped");
|
||||
net.softAPOpened = false;
|
||||
break;
|
||||
default:
|
||||
if(event > ARDUINO_EVENT_ETH_START)
|
||||
Serial.printf("Unknown Ethernet Event %d\n", event);
|
||||
Serial.printf("(evt) Unknown Ethernet Event %d\n", event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
void Network::emitHeap(uint8_t num) {
|
||||
bool bEmit = false;
|
||||
bool bTimeEmit = millis() - _lastHeapEmit > 15000;
|
||||
bool bRoomEmit = false;
|
||||
bool bValEmit = false;
|
||||
if(num != 255 || this->needsBroadcast) bEmit = true;
|
||||
if(millis() - _lastHeapEmit > 15000) bTimeEmit = true;
|
||||
uint32_t freeHeap = ESP.getFreeHeap();
|
||||
uint32_t maxHeap = ESP.getMaxAllocHeap();
|
||||
uint32_t minHeap = ESP.getMinFreeHeap();
|
||||
if(abs((int)(freeHeap - _lastHeap)) > 1500) bValEmit = true;
|
||||
if(abs((int)(maxHeap - _lastMaxHeap)) > 1500) bValEmit = true;
|
||||
bRoomEmit = sockEmit.activeClients(0) > 0;
|
||||
if(bValEmit) bTimeEmit = millis() - _lastHeapEmit > 7000;
|
||||
if(bEmit || bTimeEmit || bRoomEmit || bValEmit) {
|
||||
JsonSockEvent *json = sockEmit.beginEmit("memStatus");
|
||||
json->beginObject();
|
||||
json->addElem("max", maxHeap);
|
||||
json->addElem("free", freeHeap);
|
||||
json->addElem("min", minHeap);
|
||||
json->addElem("total", ESP.getHeapSize());
|
||||
json->endObject();
|
||||
if(num == 255 && bTimeEmit && bValEmit) {
|
||||
sockEmit.endEmit(num);
|
||||
_lastHeapEmit = millis();
|
||||
_lastHeap = freeHeap;
|
||||
_lastMaxHeap = maxHeap;
|
||||
//Serial.printf("BROAD HEAP: Emit:%d TimeEmit:%d ValEmit:%d\n", bEmit, bTimeEmit, bValEmit);
|
||||
}
|
||||
else if(num != 255) {
|
||||
sockEmit.endEmit(num);
|
||||
//Serial.printf("TARGET HEAP %d: Emit:%d TimeEmit:%d ValEmit:%d\n", num, bEmit, bTimeEmit, bValEmit);
|
||||
}
|
||||
else if(bRoomEmit) {
|
||||
sockEmit.endEmitRoom(0);
|
||||
//Serial.printf("ROOM HEAP: Emit:%d TimeEmit:%d ValEmit:%d\n", bEmit, bTimeEmit, bValEmit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
30
Network.h
30
Network.h
|
|
@ -2,6 +2,11 @@
|
|||
|
||||
#ifndef Network_h
|
||||
#define Network_h
|
||||
|
||||
//enum class conn_types_t : byte;
|
||||
|
||||
#define CONNECT_TIMEOUT 20000
|
||||
#define SSID_SCAN_INTERVAL 60000
|
||||
class Network {
|
||||
protected:
|
||||
unsigned long lastEmit = 0;
|
||||
|
|
@ -9,36 +14,45 @@ class Network {
|
|||
int lastRSSI = 0;
|
||||
int lastChannel = 0;
|
||||
int linkSpeed = 0;
|
||||
bool ethStarted = false;
|
||||
bool _connecting = false;
|
||||
public:
|
||||
unsigned long lastWifiScan = 0;
|
||||
bool ethStarted = false;
|
||||
bool wifiFallback = false;
|
||||
bool softAPOpened = false;
|
||||
bool openingSoftAP = false;
|
||||
bool needsBroadcast = true;
|
||||
conn_types connType = conn_types::unset;
|
||||
conn_types_t connType = conn_types_t::unset;
|
||||
conn_types_t connTarget = conn_types_t::unset;
|
||||
bool connected();
|
||||
bool connecting();
|
||||
void clearConnecting();
|
||||
conn_types_t preferredConnType();
|
||||
String ssid;
|
||||
String mac;
|
||||
int channel;
|
||||
int strength;
|
||||
int disconnected = 0;
|
||||
int connectAttempts = 0;
|
||||
long connectStart = 0;
|
||||
long connectTime = 0;
|
||||
uint32_t disconnectTime = 0;
|
||||
uint32_t connectStart = 0;
|
||||
uint32_t connectTime = 0;
|
||||
bool openSoftAP();
|
||||
bool connect();
|
||||
bool connectWiFi();
|
||||
bool connect(conn_types_t ctype);
|
||||
bool connectWiFi(const uint8_t *bssid = nullptr, const int32_t channel = -1);
|
||||
bool connectWired();
|
||||
void setConnected(conn_types connType);
|
||||
void setConnected(conn_types_t connType);
|
||||
bool getStrongestAP(const char *ssid, uint8_t *bssid, int32_t *channel);
|
||||
bool changeAP(const uint8_t *bssid, const int32_t channel);
|
||||
//int getStrengthByMac(const char *mac);
|
||||
int getStrengthBySSID(const char *ssid);
|
||||
//int getStrengthBySSID(const char *ssid);
|
||||
void updateHostname();
|
||||
bool setup();
|
||||
void loop();
|
||||
void end();
|
||||
void emitSockets();
|
||||
void emitSockets(uint8_t num);
|
||||
void emitHeap(uint8_t num = 255);
|
||||
uint32_t getChipId();
|
||||
static void networkEvent(WiFiEvent_t event);
|
||||
};
|
||||
|
|
|
|||
36
SSDP.cpp
36
SSDP.cpp
|
|
@ -32,7 +32,7 @@ static const char _ssdp_bye_template[] PROGMEM =
|
|||
"NTS: ssdp:byebye\r\n"
|
||||
"NT: %s\r\n"
|
||||
"USN: %s\r\n"
|
||||
"BOOTID.UPNP.ORG: %ul\r\n"
|
||||
"BOOTID.UPNP.ORG: %lu\r\n"
|
||||
"CONFIGID.UPNP.ORG: %d\r\n"
|
||||
"\r\n";
|
||||
static const char _ssdp_packet_template[] PROGMEM =
|
||||
|
|
@ -42,7 +42,7 @@ static const char _ssdp_packet_template[] PROGMEM =
|
|||
"USN: %s\r\n" // _uuid
|
||||
"%s: %s\r\n" // "NT" or "ST", _deviceType
|
||||
"LOCATION: http://%u.%u.%u.%u:%u/%s\r\n" // WiFi.localIP(), _port, _schemaURL
|
||||
"BOOTID.UPNP.ORG: %ul\r\n"
|
||||
"BOOTID.UPNP.ORG: %lu\r\n"
|
||||
"CONFIGID.UPNP.ORG: %d\r\n"
|
||||
"\r\n";
|
||||
static const char _ssdp_device_schema_template[] PROGMEM =
|
||||
|
|
@ -160,8 +160,8 @@ void UPNPDeviceType::setChipId(uint32_t chipId) {
|
|||
(uint16_t)((chipId >> 8) & 0xff),
|
||||
(uint16_t)chipId & 0xff);
|
||||
}
|
||||
SSDPClass::SSDPClass():sendQueue{false, INADDR_NONE, 0, nullptr, false, 0, ""} {}
|
||||
SSDPClass::~SSDPClass() { end(); }
|
||||
SSDPClass::SSDPClass():sendQueue{false, INADDR_NONE, 0, nullptr, false, 0, "", response_types_t::root} {}
|
||||
SSDPClass::~SSDPClass() { end(); this->isStarted = false; }
|
||||
bool SSDPClass::begin() {
|
||||
for(int i = 0; i < SSDP_QUEUE_SIZE; i++) {
|
||||
this->sendQueue[i].waiting = false;
|
||||
|
|
@ -209,6 +209,7 @@ void SSDPClass::end() {
|
|||
if(this->_server.connected()) {
|
||||
this->_sendByeBye();
|
||||
this->_server.close();
|
||||
Serial.println("Disconnected from SSDP...");
|
||||
}
|
||||
this->isStarted = false;
|
||||
// Clear out the last notified so if the user starts us up again it will notify
|
||||
|
|
@ -216,8 +217,6 @@ void SSDPClass::end() {
|
|||
for(uint8_t i = 0; i < this->m_cdeviceTypes; i++) {
|
||||
this->deviceTypes[i].lastNotified = 0;
|
||||
}
|
||||
|
||||
Serial.println("Disconnected from SSDP...");
|
||||
}
|
||||
UPNPDeviceType* SSDPClass::getDeviceType(uint8_t ndx) { if(ndx < this->m_cdeviceTypes) return &this->deviceTypes[ndx]; return nullptr; }
|
||||
UPNPDeviceType* SSDPClass::findDeviceByType(char *devType) {
|
||||
|
|
@ -407,7 +406,7 @@ void SSDPClass::_sendResponse(IPAddress addr, uint16_t port, UPNPDeviceType *d,
|
|||
strcpy_P(pbuff, _ssdp_response_template);
|
||||
|
||||
// Don't use ip.toString as this fragments the heap like no tomorrow.
|
||||
int len = snprintf_P(buffer, sizeof(buffer)-1,
|
||||
snprintf_P(buffer, sizeof(buffer)-1,
|
||||
_ssdp_packet_template,
|
||||
pbuff,
|
||||
this->_interval,
|
||||
|
|
@ -418,28 +417,6 @@ void SSDPClass::_sendResponse(IPAddress addr, uint16_t port, UPNPDeviceType *d,
|
|||
buffer[sizeof(buffer) - 1] = '\0';
|
||||
this->_sendResponse(addr, port, buffer);
|
||||
free(pbuff);
|
||||
/*
|
||||
static const char _ssdp_packet_template[] PROGMEM =
|
||||
"%s" // _ssdp_response_template / _ssdp_notify_template
|
||||
"CACHE-CONTROL: max-age=%u\r\n" // _interval
|
||||
"SERVER: Arduino/1.0 UPNP/1.1 %s/%s\r\n" // _modelName, _modelNumber
|
||||
"USN: %s\r\n" // _uuid
|
||||
"%s: %s\r\n" // "NT" or "ST", _deviceType
|
||||
"LOCATION: http://%u.%u.%u.%u:%u/%s\r\n" // WiFi.localIP(), _port, _schemaURL
|
||||
"\r\n";
|
||||
|
||||
|
||||
|
||||
#ifdef DEBUG_SSDP
|
||||
DEBUG_SSDP.print("Sending Response to ");
|
||||
DEBUG_SSDP.print(IPAddress(addr));
|
||||
DEBUG_SSDP.print(":");
|
||||
DEBUG_SSDP.println(port);
|
||||
DEBUG_SSDP.println(buffer);
|
||||
#endif
|
||||
|
||||
_server.writeTo((const uint8_t *)buffer, len, addr, port);
|
||||
*/
|
||||
}
|
||||
void SSDPClass::_sendResponse(IPAddress addr, uint16_t port, const char *buff) {
|
||||
#ifdef DEBUG_SSDP
|
||||
|
|
@ -545,6 +522,7 @@ void SSDPClass::_sendNotify(UPNPDeviceType *d, bool root) {
|
|||
ip[0], ip[1], ip[2], ip[3], _port, d->schemaURL, this->bootId, this->configId);
|
||||
this->_sendNotify(buffer);
|
||||
d->lastNotified = millis();
|
||||
free(pbuff);
|
||||
}
|
||||
void SSDPClass::setActive(uint8_t ndx, bool isActive) {
|
||||
UPNPDeviceType *d = &this->deviceTypes[ndx];
|
||||
|
|
|
|||
137
Sockets.cpp
137
Sockets.cpp
|
|
@ -1,6 +1,7 @@
|
|||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <WebSocketsServer.h>
|
||||
#include <esp_task_wdt.h>
|
||||
#include "Sockets.h"
|
||||
#include "ConfigSettings.h"
|
||||
#include "Somfy.h"
|
||||
|
|
@ -16,6 +17,9 @@ extern GitUpdater git;
|
|||
|
||||
WebSocketsServer sockServer = WebSocketsServer(8080);
|
||||
|
||||
#define MAX_SOCK_RESPONSE 2048
|
||||
static char g_response[MAX_SOCK_RESPONSE];
|
||||
|
||||
bool room_t::isJoined(uint8_t num) {
|
||||
for(uint8_t i = 0; i < sizeof(this->clients); i++) {
|
||||
if(this->clients[i] == num) return true;
|
||||
|
|
@ -39,6 +43,9 @@ bool room_t::leave(uint8_t num) {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
void room_t::clear() {
|
||||
memset(this->clients, 255, sizeof(this->clients));
|
||||
}
|
||||
uint8_t room_t::activeClients() {
|
||||
uint8_t n = 0;
|
||||
for(uint8_t i = 0; i < sizeof(this->clients); i++) {
|
||||
|
|
@ -49,7 +56,9 @@ uint8_t room_t::activeClients() {
|
|||
/*********************************************************************
|
||||
* ClientSocketEvent class members
|
||||
********************************************************************/
|
||||
/*
|
||||
void ClientSocketEvent::prepareMessage(const char *evt, const char *payload) {
|
||||
if(strlen(payload) + 5 >= sizeof(this->msg)) Serial.printf("Socket buffer overflow %d > 2048\n", strlen(payload) + 5 + strlen(evt));
|
||||
snprintf(this->msg, sizeof(this->msg), "42[%s,%s]", evt, payload);
|
||||
}
|
||||
void ClientSocketEvent::prepareMessage(const char *evt, JsonDocument &doc) {
|
||||
|
|
@ -58,6 +67,7 @@ void ClientSocketEvent::prepareMessage(const char *evt, JsonDocument &doc) {
|
|||
serializeJson(doc, &this->msg[strlen(this->msg)], sizeof(this->msg) - strlen(this->msg) - 2);
|
||||
strcat(this->msg, "]");
|
||||
}
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
* SocketEmitter class members
|
||||
|
|
@ -70,102 +80,60 @@ void SocketEmitter::begin() {
|
|||
sockServer.enableHeartbeat(20000, 10000, 3);
|
||||
sockServer.onEvent(this->wsEvent);
|
||||
Serial.println("Socket Server Started...");
|
||||
settings.printAvailHeap();
|
||||
//settings.printAvailHeap();
|
||||
}
|
||||
void SocketEmitter::loop() {
|
||||
this->initClients();
|
||||
sockServer.loop();
|
||||
}
|
||||
/*
|
||||
bool SocketEmitter::sendToClients(const char *evt, JsonObject &obj) {
|
||||
serializeJson(obj, g_buffer, sizeof(g_buffer));
|
||||
return this->sendToClients(evt, g_buffer);
|
||||
JsonSockEvent *SocketEmitter::beginEmit(const char *evt) {
|
||||
this->json.beginEvent(&sockServer, evt, g_response, sizeof(g_response));
|
||||
return &this->json;
|
||||
}
|
||||
bool SocketEmitter::sendToClient(uint8_t num, const char *evt, JsonObject &obj) {
|
||||
serializeJson(obj, g_buffer, sizeof(g_buffer));
|
||||
return this->sendToClient(num, evt, g_buffer);
|
||||
}
|
||||
*/
|
||||
ClientSocketEvent::ClientSocketEvent() {}
|
||||
ClientSocketEvent::ClientSocketEvent(const char *evt) { snprintf(this->msg, sizeof(this->msg), "42[%s,]", evt); }
|
||||
ClientSocketEvent::ClientSocketEvent(const char *evt, const char *payload) { snprintf(this->msg, sizeof(this->msg), "42[%s,%s]", evt, payload); }
|
||||
void ClientSocketEvent::appendMessage(const char *text) {
|
||||
uint16_t len = strlen(this->msg);
|
||||
this->msg[len - 1] = '\0';
|
||||
strcat(this->msg, text);
|
||||
strcat(this->msg, "]");
|
||||
}
|
||||
/*
|
||||
void ClientSocketEvent::appendJSONElem(const char *elem) {
|
||||
this->msg[strlen(this->msg) - 1] = '\0'; // Trim off the ending bracket.
|
||||
uint16_t len = strlen(this->msg);
|
||||
if(len > 0) {
|
||||
if(this->msg[strlen(this->msg) - 1] == '{') strcat(this->msg, ',');
|
||||
void SocketEmitter::endEmit(uint8_t num) { this->json.endEvent(num); sockServer.loop(); }
|
||||
void SocketEmitter::endEmitRoom(uint8_t room) {
|
||||
if(room < SOCK_MAX_ROOMS) {
|
||||
room_t *r = &this->rooms[room];
|
||||
for(uint8_t i = 0; i < sizeof(r->clients); i++) {
|
||||
if(r->clients[i] != 255) this->json.endEvent(r->clients[i]);
|
||||
}
|
||||
}
|
||||
strcat(this->msg, "\"");
|
||||
strcat(this->msg, elem);
|
||||
strcat(this->msg, "\":");
|
||||
strcat(this->msg, "]");
|
||||
}
|
||||
void ClientSocketEvent::appendJSON(const char *elem, const char *text, bool quoted) {
|
||||
this->appendJSONElem(elem);
|
||||
this->msg[strlen(this->msg) - 1] = '\0'; // Trim off the ending bracket.
|
||||
if(quoted) strcat(this->msg, "\"");
|
||||
strcat(this->msg, text);
|
||||
if(quoted) strcat(this->msg, "\"");
|
||||
strcat(this->msg, "]");
|
||||
}
|
||||
void ClientSocketEvent::appendJSON(const char *elem, const bool b) { this->appendJSON(elem, b ? "true" : "false", false); }
|
||||
void ClientSocketEvent::appendJSON(const char *elem, const uint8_t val) {
|
||||
char buff[5];
|
||||
sprintf(buff, "%d", val);
|
||||
this->appendJSON(elem, buff, false);
|
||||
}
|
||||
*/
|
||||
|
||||
uint8_t SocketEmitter::activeClients(uint8_t room) {
|
||||
if(room < SOCK_MAX_ROOMS) return this->rooms[room].activeClients();
|
||||
return 0;
|
||||
}
|
||||
bool SocketEmitter::sendToRoom(uint8_t room, ClientSocketEvent *evt) {
|
||||
if(room < SOCK_MAX_ROOMS) {
|
||||
room_t *r = &this->rooms[room];
|
||||
for(uint8_t i = 0; i < sizeof(r->clients); i++) {
|
||||
if(r->clients[i] != 255) this->sendToClient(r->clients[i], evt);
|
||||
void SocketEmitter::initClients() {
|
||||
for(uint8_t i = 0; i < sizeof(this->newClients); i++) {
|
||||
uint8_t num = this->newClients[i];
|
||||
if(num != 255) {
|
||||
if(sockServer.clientIsConnected(num)) {
|
||||
Serial.printf("Initializing Socket Client %u\n", num);
|
||||
esp_task_wdt_reset();
|
||||
settings.emitSockets(num);
|
||||
somfy.emitState(num);
|
||||
git.emitUpdateCheck(num);
|
||||
net.emitSockets(num);
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
this->newClients[i] = 255;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool SocketEmitter::sendToClients(ClientSocketEvent *evt) {
|
||||
if(evt->msg[strlen(evt->msg) - 1] != ']') strcat(evt->msg, "]");
|
||||
return sockServer.broadcastTXT(evt->msg);
|
||||
void SocketEmitter::delayInit(uint8_t num) {
|
||||
for(uint8_t i=0; i < sizeof(this->newClients); i++) {
|
||||
if(this->newClients[i] == num) break;
|
||||
else if(this->newClients[i] == 255) {
|
||||
this->newClients[i] = num;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool SocketEmitter::sendToClient(uint8_t num, ClientSocketEvent *evt) {
|
||||
if(evt->msg[strlen(evt->msg) - 1] != ']') strcat(evt->msg, "]");
|
||||
return sockServer.sendTXT(num, evt->msg);
|
||||
void SocketEmitter::end() {
|
||||
sockServer.close();
|
||||
for(uint8_t i = 0; i < SOCK_MAX_ROOMS; i++)
|
||||
this->rooms[i].clear();
|
||||
}
|
||||
bool SocketEmitter::sendToClients(const char *evt, const char *payload) {
|
||||
if(settings.status == DS_FWUPDATE) return true;
|
||||
this->evt.prepareMessage(evt, payload);
|
||||
return sockServer.broadcastTXT(this->evt.msg);
|
||||
}
|
||||
bool SocketEmitter::sendToClient(uint8_t num, const char *evt, const char *payload) {
|
||||
if(settings.status == DS_FWUPDATE) return true;
|
||||
this->evt.prepareMessage(evt, payload);
|
||||
return sockServer.sendTXT(num, this->evt.msg);
|
||||
}
|
||||
bool SocketEmitter::sendToClient(uint8_t num, const char *evt, JsonDocument &doc) {
|
||||
if(settings.status == DS_FWUPDATE) return true;
|
||||
this->evt.prepareMessage(evt, doc);
|
||||
return sockServer.sendTXT(num, this->evt.msg);
|
||||
}
|
||||
bool SocketEmitter::sendToClients(const char *evt, JsonDocument &doc) {
|
||||
if(settings.status == DS_FWUPDATE) return true;
|
||||
this->evt.prepareMessage(evt, doc);
|
||||
return sockServer.broadcastTXT(this->evt.msg);
|
||||
}
|
||||
|
||||
void SocketEmitter::end() { sockServer.close(); }
|
||||
void SocketEmitter::disconnect() { sockServer.disconnect(); }
|
||||
void SocketEmitter::wsEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length) {
|
||||
switch(type) {
|
||||
|
|
@ -190,13 +158,8 @@ void SocketEmitter::wsEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t
|
|||
Serial.printf("Socket [%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
|
||||
// Send all the current shade settings to the client.
|
||||
sockServer.sendTXT(num, "Connected");
|
||||
sockServer.loop();
|
||||
settings.emitSockets(num);
|
||||
somfy.emitState(num);
|
||||
git.emitUpdateCheck(num);
|
||||
net.emitSockets(num);
|
||||
sockServer.loop();
|
||||
net.needsBroadcast = true;
|
||||
//sockServer.loop();
|
||||
sockEmit.delayInit(num);
|
||||
}
|
||||
break;
|
||||
case WStype_TEXT:
|
||||
|
|
|
|||
38
Sockets.h
38
Sockets.h
|
|
@ -1,4 +1,5 @@
|
|||
#include <WebSocketsServer.h>
|
||||
#include "WResp.h"
|
||||
#ifndef sockets_h
|
||||
#define sockets_h
|
||||
|
||||
|
|
@ -6,45 +7,32 @@
|
|||
#define ROOM_EMIT_FRAME 0
|
||||
|
||||
struct room_t {
|
||||
uint8_t clients[5] = {255, 255, 255, 255};
|
||||
uint8_t clients[5] = {255, 255, 255, 255, 255};
|
||||
uint8_t activeClients();
|
||||
bool isJoined(uint8_t num);
|
||||
bool join(uint8_t num);
|
||||
bool leave(uint8_t num);
|
||||
};
|
||||
|
||||
|
||||
class ClientSocketEvent {
|
||||
public:
|
||||
ClientSocketEvent();
|
||||
ClientSocketEvent(const char *evt);
|
||||
ClientSocketEvent(const char *evt, const char *data);
|
||||
char msg[2048];
|
||||
void prepareMessage(const char *evt, const char *data);
|
||||
void prepareMessage(const char *evt, JsonDocument &doc);
|
||||
void appendMessage(const char *text);
|
||||
void appendElement(const char *elem, const char *val);
|
||||
|
||||
|
||||
void clear();
|
||||
};
|
||||
class SocketEmitter {
|
||||
ClientSocketEvent evt;
|
||||
|
||||
protected:
|
||||
uint8_t newclients = 0;
|
||||
uint8_t newClients[5] = {255,255,255,255,255};
|
||||
void delayInit(uint8_t num);
|
||||
public:
|
||||
JsonSockEvent json;
|
||||
//ClientSocketEvent evt;
|
||||
room_t rooms[SOCK_MAX_ROOMS];
|
||||
uint8_t activeClients(uint8_t room);
|
||||
void initClients();
|
||||
void startup();
|
||||
void begin();
|
||||
void loop();
|
||||
void end();
|
||||
void disconnect();
|
||||
bool sendToRoom(uint8_t room, ClientSocketEvent *evt);
|
||||
bool sendToClients(ClientSocketEvent *evt);
|
||||
bool sendToClient(uint8_t num, ClientSocketEvent *evt);
|
||||
bool sendToClients(const char *evt, const char *data);
|
||||
bool sendToClient(uint8_t num, const char *evt, const char *data);
|
||||
bool sendToClients(const char *evt, JsonDocument &doc);
|
||||
bool sendToClient(uint8_t num, const char *evt, JsonDocument &doc);
|
||||
JsonSockEvent * beginEmit(const char *evt);
|
||||
void endEmit(uint8_t num = 255);
|
||||
void endEmitRoom(uint8_t num);
|
||||
static void wsEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length);
|
||||
};
|
||||
#endif
|
||||
|
|
|
|||
58
Somfy.h
58
Somfy.h
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef SOMFY_H
|
||||
#define SOMFY_H
|
||||
#include "ConfigSettings.h"
|
||||
#include "WResp.h"
|
||||
|
||||
#define SOMFY_MAX_SHADES 32
|
||||
#define SOMFY_MAX_GROUPS 16
|
||||
|
|
@ -46,6 +47,8 @@ enum class somfy_commands : byte {
|
|||
RTWProto = 0xF, // RTW Protocol
|
||||
// Command extensions for 80 bit frames
|
||||
StepUp = 0x8B,
|
||||
Favorite = 0xC1,
|
||||
Stop = 0xF1
|
||||
};
|
||||
enum class group_types : byte {
|
||||
channel = 0x00
|
||||
|
|
@ -64,7 +67,10 @@ enum class shade_types : byte {
|
|||
drycontact2 = 0x0A,
|
||||
lgate = 0x0B,
|
||||
cgate = 0x0C,
|
||||
rgate = 0x0D
|
||||
rgate = 0x0D,
|
||||
lgate1 = 0x0E,
|
||||
cgate1 = 0x0F,
|
||||
rgate1 = 0x10
|
||||
};
|
||||
enum class tilt_types : byte {
|
||||
none = 0x00,
|
||||
|
|
@ -154,7 +160,8 @@ enum class somfy_flags_t : byte {
|
|||
Light = 0x08,
|
||||
Windy = 0x10,
|
||||
Sunny = 0x20,
|
||||
Lighted = 0x40
|
||||
Lighted = 0x40,
|
||||
SimMy = 0x80
|
||||
};
|
||||
enum class gpio_flags_t : byte {
|
||||
LowLevelTrigger = 0x01
|
||||
|
|
@ -167,6 +174,7 @@ struct somfy_relay_t {
|
|||
struct somfy_frame_t {
|
||||
bool valid = false;
|
||||
bool processed = false;
|
||||
bool synonym = false;
|
||||
radio_proto proto = radio_proto::RTS;
|
||||
int rssi = 0;
|
||||
byte lqi = 0x0;
|
||||
|
|
@ -180,11 +188,16 @@ struct somfy_frame_t {
|
|||
uint32_t await = 0;
|
||||
uint8_t bitLength = 56;
|
||||
uint16_t pulseCount = 0;
|
||||
uint8_t stepSize = 0;
|
||||
void print();
|
||||
void encode80BitFrame(byte *frame, uint8_t repeat);
|
||||
byte calc80Checksum(byte b0, byte b1, byte b2);
|
||||
byte encode80Byte7(byte start, uint8_t repeat);
|
||||
void encodeFrame(byte *frame);
|
||||
void decodeFrame(byte* frame);
|
||||
void decodeFrame(somfy_rx_t *rx);
|
||||
bool isRepeat(somfy_frame_t &f);
|
||||
bool isSynonym(somfy_frame_t &f);
|
||||
void copy(somfy_frame_t &f);
|
||||
};
|
||||
|
||||
|
|
@ -196,7 +209,7 @@ class SomfyRoom {
|
|||
void clear();
|
||||
bool save();
|
||||
bool fromJSON(JsonObject &obj);
|
||||
bool toJSON(JsonObject &obj);
|
||||
void toJSON(JsonResponse &json);
|
||||
void emitState(const char *evt = "roomState");
|
||||
void emitState(uint8_t num, const char *evt = "roomState");
|
||||
void publish();
|
||||
|
|
@ -226,17 +239,19 @@ class SomfyRemote {
|
|||
uint8_t repeats = 1;
|
||||
virtual bool isLastCommand(somfy_commands cmd);
|
||||
char *getRemotePrefId() {return m_remotePrefId;}
|
||||
virtual bool toJSON(JsonObject &obj);
|
||||
virtual void toJSON(JsonResponse &json);
|
||||
virtual void setRemoteAddress(uint32_t address);
|
||||
virtual uint32_t getRemoteAddress();
|
||||
virtual uint16_t getNextRollingCode();
|
||||
virtual uint16_t setRollingCode(uint16_t code);
|
||||
bool hasSunSensor();
|
||||
bool hasLight();
|
||||
bool simMy();
|
||||
void setSunSensor(bool bHasSensor);
|
||||
void setLight(bool bHasLight);
|
||||
void setSimMy(bool bSimMy);
|
||||
virtual void sendCommand(somfy_commands cmd);
|
||||
virtual void sendCommand(somfy_commands cmd, uint8_t repeat);
|
||||
virtual void sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSize = 0);
|
||||
void sendSensorCommand(int8_t isWindy, int8_t isSunny, uint8_t repeat);
|
||||
void repeatFrame(uint8_t repeat);
|
||||
virtual uint16_t p_lastRollingCode(uint16_t code);
|
||||
|
|
@ -277,10 +292,8 @@ class SomfyShade : public SomfyRemote {
|
|||
#ifdef USE_NVS
|
||||
void load();
|
||||
#endif
|
||||
//somfy_tx_queue_t txQueue;
|
||||
float currentPos = 0.0f;
|
||||
float currentTiltPos = 0.0f;
|
||||
//uint16_t movement = 0;
|
||||
int8_t lastMovement = 0;
|
||||
int8_t direction = 0; // 0 = stopped, 1=down, -1=up.
|
||||
int8_t tiltDirection = 0; // 0=stopped, 1=clockwise, -1=counter clockwise
|
||||
|
|
@ -291,9 +304,10 @@ class SomfyShade : public SomfyRemote {
|
|||
SomfyLinkedRemote linkedRemotes[SOMFY_MAX_LINKED_REMOTES];
|
||||
bool paired = false;
|
||||
int8_t validateJSON(JsonObject &obj);
|
||||
bool toJSONRef(JsonObject &obj);
|
||||
void toJSONRef(JsonResponse &json);
|
||||
int8_t fromJSON(JsonObject &obj);
|
||||
bool toJSON(JsonObject &obj) override;
|
||||
void toJSON(JsonResponse &json) override;
|
||||
|
||||
char name[21] = "";
|
||||
void setShadeId(uint8_t id) { shadeId = id; }
|
||||
uint8_t getShadeId() { return shadeId; }
|
||||
|
|
@ -311,11 +325,12 @@ class SomfyShade : public SomfyRemote {
|
|||
void setMovement(int8_t dir);
|
||||
void setTarget(float target);
|
||||
bool isAtTarget();
|
||||
bool isToggle();
|
||||
void moveToTarget(float pos, float tilt = -1.0f);
|
||||
void moveToTiltTarget(float target);
|
||||
void sendTiltCommand(somfy_commands cmd);
|
||||
void sendCommand(somfy_commands cmd);
|
||||
void sendCommand(somfy_commands cmd, uint8_t repeat);
|
||||
void sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSize = 0);
|
||||
bool linkRemote(uint32_t remoteAddress, uint16_t rollingCode = 0);
|
||||
bool unlinkRemote(uint32_t remoteAddress);
|
||||
void emitState(const char *evt = "shadeState");
|
||||
|
|
@ -377,7 +392,10 @@ class SomfyGroup : public SomfyRemote {
|
|||
bool save();
|
||||
void clear();
|
||||
bool fromJSON(JsonObject &obj);
|
||||
bool toJSON(JsonObject &obj);
|
||||
//bool toJSON(JsonObject &obj);
|
||||
void toJSON(JsonResponse &json);
|
||||
void toJSONRef(JsonResponse &json);
|
||||
|
||||
bool linkShade(uint8_t shadeId);
|
||||
bool unlinkShade(uint8_t shadeId);
|
||||
bool hasShadeId(uint8_t shadeId);
|
||||
|
|
@ -391,7 +409,7 @@ class SomfyGroup : public SomfyRemote {
|
|||
void emitState(const char *evt = "groupState");
|
||||
void emitState(uint8_t num, const char *evt = "groupState");
|
||||
void sendCommand(somfy_commands cmd);
|
||||
void sendCommand(somfy_commands cmd, uint8_t repeat);
|
||||
void sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSize = 0);
|
||||
int8_t p_direction(int8_t dir);
|
||||
bool publish(const char *topic, uint8_t val, bool retain = false);
|
||||
bool publish(const char *topic, int8_t val, bool retain = false);
|
||||
|
|
@ -466,7 +484,8 @@ struct transceiver_config_t {
|
|||
bool appendStatus = false; // Appends the RSSI and LQI values to the TX packed as well as the CRC.
|
||||
*/
|
||||
void fromJSON(JsonObject& obj);
|
||||
void toJSON(JsonObject& obj);
|
||||
//void toJSON(JsonObject& obj);
|
||||
void toJSON(JsonResponse& json);
|
||||
void save();
|
||||
void load();
|
||||
void apply();
|
||||
|
|
@ -480,7 +499,8 @@ class Transceiver {
|
|||
public:
|
||||
transceiver_config_t config;
|
||||
bool printBuffer = false;
|
||||
bool toJSON(JsonObject& obj);
|
||||
//bool toJSON(JsonObject& obj);
|
||||
void toJSON(JsonResponse& json);
|
||||
bool fromJSON(JsonObject& obj);
|
||||
bool save();
|
||||
bool begin();
|
||||
|
|
@ -537,12 +557,10 @@ class SomfyShadeController {
|
|||
SomfyGroup groups[SOMFY_MAX_GROUPS];
|
||||
bool linkRepeater(uint32_t address);
|
||||
bool unlinkRepeater(uint32_t address);
|
||||
bool toJSON(DynamicJsonDocument &doc);
|
||||
bool toJSON(JsonObject &obj);
|
||||
bool toJSONRooms(JsonArray &arr);
|
||||
bool toJSONShades(JsonArray &arr);
|
||||
bool toJSONGroups(JsonArray &arr);
|
||||
bool toJSONRepeaters(JsonArray &arr);
|
||||
void toJSONShades(JsonResponse &json);
|
||||
void toJSONRooms(JsonResponse &json);
|
||||
void toJSONGroups(JsonResponse &json);
|
||||
void toJSONRepeaters(JsonResponse &json);
|
||||
uint8_t repeaterCount();
|
||||
uint8_t roomCount();
|
||||
uint8_t shadeCount();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include <WiFi.h>
|
||||
#include <LittleFS.h>
|
||||
#include <esp_task_wdt.h>
|
||||
#include "ConfigSettings.h"
|
||||
#include "Network.h"
|
||||
#include "Web.h"
|
||||
|
|
@ -36,6 +37,9 @@ void setup() {
|
|||
net.setup();
|
||||
somfy.begin();
|
||||
//git.checkForUpdate();
|
||||
esp_task_wdt_init(7, true); //enable panic so ESP32 restarts
|
||||
esp_task_wdt_add(NULL); //add current thread to WDT watch
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
|
@ -45,35 +49,38 @@ void loop() {
|
|||
Serial.print("Rebooting after ");
|
||||
Serial.print(rebootDelay.rebootTime);
|
||||
Serial.println("ms");
|
||||
net.end();
|
||||
ESP.restart();
|
||||
return;
|
||||
}
|
||||
uint32_t timing = millis();
|
||||
|
||||
net.loop();
|
||||
if(millis() - timing > 100) Serial.printf("Timing Net: %ldms\n", millis() - timing);
|
||||
timing = millis();
|
||||
esp_task_wdt_reset();
|
||||
somfy.loop();
|
||||
if(millis() - timing > 100) Serial.printf("Timing Somfy: %ldms\n", millis() - timing);
|
||||
timing = millis();
|
||||
if(net.connected()) {
|
||||
if(!rebootDelay.reboot) git.loop();
|
||||
esp_task_wdt_reset();
|
||||
if(net.connected() || net.softAPOpened) {
|
||||
if(!rebootDelay.reboot && net.connected() && !net.softAPOpened) {
|
||||
git.loop();
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
webServer.loop();
|
||||
if(millis() - timing > 200) Serial.printf("Timing WebServer: %ldms\n", millis() - timing);
|
||||
esp_task_wdt_reset();
|
||||
if(millis() - timing > 100) Serial.printf("Timing WebServer: %ldms\n", millis() - timing);
|
||||
esp_task_wdt_reset();
|
||||
timing = millis();
|
||||
sockEmit.loop();
|
||||
if(millis() - timing > 100) Serial.printf("Timing Socket: %ldms\n", millis() - timing);
|
||||
esp_task_wdt_reset();
|
||||
timing = millis();
|
||||
}
|
||||
if(rebootDelay.reboot && millis() > rebootDelay.rebootTime) {
|
||||
net.end();
|
||||
ESP.restart();
|
||||
}
|
||||
/*
|
||||
if(heap < oldheap) {
|
||||
Serial.print("Heap: ");
|
||||
Serial.print(oldheap);
|
||||
Serial.print(" -> ");
|
||||
Serial.println(heap);
|
||||
}
|
||||
oldheap = heap;
|
||||
*/
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -36,7 +36,14 @@ time_t Timestamp::mkUTCTime(struct tm *dt) {
|
|||
return tsBadLocal + tsLocalOffset;
|
||||
}
|
||||
time_t Timestamp::parseUTCTime(const char *buff) {
|
||||
struct tm dt = {0};
|
||||
struct tm dt;
|
||||
dt.tm_hour = 0;
|
||||
dt.tm_mday = 0;
|
||||
dt.tm_mon = 0;
|
||||
dt.tm_year = 0;
|
||||
dt.tm_wday = 0;
|
||||
dt.tm_yday = 0;
|
||||
dt.tm_isdst = false;
|
||||
char num[5];
|
||||
uint8_t i = 0;
|
||||
memset(num, 0x00, sizeof(num));
|
||||
|
|
|
|||
3
Utils.h
3
Utils.h
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
|
||||
[[maybe_unused]] static void SETCHARPROP(char *prop, const char *value, size_t size) {strncpy(prop, value, size); prop[size - 1] = '\0';}
|
||||
/*
|
||||
namespace util {
|
||||
// Createa a custom to_string function. C++ can be annoying
|
||||
// with all the trailing 0s on number formats.
|
||||
|
|
@ -23,6 +24,8 @@ namespace util {
|
|||
return str;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
static void _ltrim(char *str) {
|
||||
int s = 0, j, k = 0;
|
||||
int e = strlen(str);
|
||||
|
|
|
|||
204
WResp.cpp
Normal file
204
WResp.cpp
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
#include "WResp.h"
|
||||
void JsonSockEvent::beginEvent(WebSocketsServer *server, const char *evt, char *buff, size_t buffSize) {
|
||||
this->server = server;
|
||||
this->buff = buff;
|
||||
this->buffSize = buffSize;
|
||||
this->_nocomma = true;
|
||||
this->_closed = false;
|
||||
snprintf(this->buff, buffSize, "42[%s,", evt);
|
||||
}
|
||||
void JsonSockEvent::closeEvent() {
|
||||
if(!this->_closed) {
|
||||
if(strlen(this->buff) < buffSize) strcat(this->buff, "]");
|
||||
else this->buff[buffSize - 1] = ']';
|
||||
}
|
||||
this->_nocomma = true;
|
||||
this->_closed = true;
|
||||
}
|
||||
void JsonSockEvent::endEvent(uint8_t num) {
|
||||
this->closeEvent();
|
||||
if(num == 255) this->server->broadcastTXT(this->buff);
|
||||
else this->server->sendTXT(num, this->buff);
|
||||
}
|
||||
void JsonSockEvent::_safecat(const char *val, bool escape) {
|
||||
size_t len = (escape ? this->calcEscapedLength(val) : strlen(val)) + strlen(this->buff);
|
||||
if(escape) len += 2;
|
||||
if(len >= this->buffSize) {
|
||||
Serial.printf("Socket exceeded buffer size %d - %d\n", this->buffSize, len);
|
||||
Serial.println(this->buff);
|
||||
return;
|
||||
}
|
||||
if(escape) strcat(this->buff, "\"");
|
||||
if(escape) this->escapeString(val, &this->buff[strlen(this->buff)]);
|
||||
else strcat(this->buff, val);
|
||||
if(escape) strcat(this->buff, "\"");
|
||||
}
|
||||
void JsonResponse::beginResponse(WebServer *server, char *buff, size_t buffSize) {
|
||||
this->server = server;
|
||||
this->buff = buff;
|
||||
this->buffSize = buffSize;
|
||||
this->buff[0] = 0x00;
|
||||
this->_nocomma = true;
|
||||
server->setContentLength(CONTENT_LENGTH_UNKNOWN);
|
||||
}
|
||||
void JsonResponse::endResponse() {
|
||||
if(strlen(buff)) this->send();
|
||||
server->sendContent("", 0);
|
||||
}
|
||||
void JsonResponse::send() {
|
||||
if(!this->_headersSent) server->send_P(200, "application/json", this->buff);
|
||||
else server->sendContent(this->buff);
|
||||
//Serial.printf("Sent %d bytes %d\n", strlen(this->buff), this->buffSize);
|
||||
this->buff[0] = 0x00;
|
||||
this->_headersSent = true;
|
||||
}
|
||||
void JsonResponse::_safecat(const char *val, bool escape) {
|
||||
size_t len = (escape ? this->calcEscapedLength(val) : strlen(val)) + strlen(this->buff);
|
||||
if(escape) len += 2;
|
||||
if(len >= this->buffSize) {
|
||||
this->send();
|
||||
}
|
||||
if(escape) strcat(this->buff, "\"");
|
||||
if(escape) this->escapeString(val, &this->buff[strlen(this->buff)]);
|
||||
else strcat(this->buff, val);
|
||||
if(escape) strcat(this->buff, "\"");
|
||||
}
|
||||
|
||||
void JsonFormatter::beginObject(const char *name) {
|
||||
if(name && strlen(name) > 0) this->appendElem(name);
|
||||
else if(!this->_nocomma) this->_safecat(",");
|
||||
this->_safecat("{");
|
||||
this->_objects++;
|
||||
this->_nocomma = true;
|
||||
}
|
||||
void JsonFormatter::endObject() {
|
||||
//if(strlen(this->buff) + 1 > this->buffSize - 1) this->send();
|
||||
this->_safecat("}");
|
||||
this->_objects--;
|
||||
this->_nocomma = false;
|
||||
}
|
||||
void JsonFormatter::beginArray(const char *name) {
|
||||
if(name && strlen(name) > 0) this->appendElem(name);
|
||||
else if(!this->_nocomma) this->_safecat(",");
|
||||
this->_safecat("[");
|
||||
this->_arrays++;
|
||||
this->_nocomma = true;
|
||||
}
|
||||
void JsonFormatter::endArray() {
|
||||
//if(strlen(this->buff) + 1 > this->buffSize - 1) this->send();
|
||||
this->_safecat("]");
|
||||
this->_arrays--;
|
||||
this->_nocomma = false;
|
||||
}
|
||||
|
||||
void JsonFormatter::appendElem(const char *name) {
|
||||
if(!this->_nocomma) this->_safecat(",");
|
||||
if(name && strlen(name) > 0) {
|
||||
this->_safecat(name, true);
|
||||
this->_safecat(":");
|
||||
}
|
||||
this->_nocomma = false;
|
||||
}
|
||||
|
||||
void JsonFormatter::addElem(const char *name, const char *val) {
|
||||
if(!val) return;
|
||||
this->appendElem(name);
|
||||
this->_safecat(val, true);
|
||||
}
|
||||
void JsonFormatter::addElem(const char *val) { this->addElem(nullptr, val); }
|
||||
void JsonFormatter::addElem(float fval) { sprintf(this->_numbuff, "%.4f", fval); this->_appendNumber(nullptr); }
|
||||
void JsonFormatter::addElem(int8_t nval) { sprintf(this->_numbuff, "%d", nval); this->_appendNumber(nullptr); }
|
||||
void JsonFormatter::addElem(uint8_t nval) { sprintf(this->_numbuff, "%u", nval); this->_appendNumber(nullptr); }
|
||||
void JsonFormatter::addElem(int32_t nval) { sprintf(this->_numbuff, "%ld", (long)nval); this->_appendNumber(nullptr); }
|
||||
void JsonFormatter::addElem(uint32_t nval) { sprintf(this->_numbuff, "%lu", (unsigned long)nval); this->_appendNumber(nullptr); }
|
||||
|
||||
/*
|
||||
void JsonFormatter::addElem(int16_t nval) { sprintf(this->_numbuff, "%d", nval); this->_appendNumber(nullptr); }
|
||||
void JsonFormatter::addElem(uint16_t nval) { sprintf(this->_numbuff, "%u", nval); this->_appendNumber(nullptr); }
|
||||
void JsonFormatter::addElem(int64_t lval) { sprintf(this->_numbuff, "%lld", (long long)lval); this->_appendNumber(nullptr); }
|
||||
void JsonFormatter::addElem(uint64_t lval) { sprintf(this->_numbuff, "%llu", (unsigned long long)lval); this->_appendNumber(nullptr); }
|
||||
*/
|
||||
void JsonFormatter::addElem(bool bval) { strcpy(this->_numbuff, bval ? "true" : "false"); this->_appendNumber(nullptr); }
|
||||
|
||||
void JsonFormatter::addElem(const char *name, float fval) { sprintf(this->_numbuff, "%.4f", fval); this->_appendNumber(name); }
|
||||
void JsonFormatter::addElem(const char *name, int8_t nval) { sprintf(this->_numbuff, "%d", nval); this->_appendNumber(name); }
|
||||
void JsonFormatter::addElem(const char *name, uint8_t nval) { sprintf(this->_numbuff, "%u", nval); this->_appendNumber(name); }
|
||||
void JsonFormatter::addElem(const char *name, int32_t nval) { sprintf(this->_numbuff, "%ld", (long)nval); this->_appendNumber(name); }
|
||||
void JsonFormatter::addElem(const char *name, uint32_t nval) { sprintf(this->_numbuff, "%lu", (unsigned long)nval); this->_appendNumber(name); }
|
||||
|
||||
/*
|
||||
void JsonFormatter::addElem(const char *name, int16_t nval) { sprintf(this->_numbuff, "%d", nval); this->_appendNumber(name); }
|
||||
void JsonFormatter::addElem(const char *name, uint16_t nval) { sprintf(this->_numbuff, "%u", nval); this->_appendNumber(name); }
|
||||
void JsonFormatter::addElem(const char *name, int64_t lval) { sprintf(this->_numbuff, "%lld", (long long)lval); this->_appendNumber(name); }
|
||||
void JsonFormatter::addElem(const char *name, uint64_t lval) { sprintf(this->_numbuff, "%llu", (unsigned long long)lval); this->_appendNumber(name); }
|
||||
*/
|
||||
void JsonFormatter::addElem(const char *name, bool bval) { strcpy(this->_numbuff, bval ? "true" : "false"); this->_appendNumber(name); }
|
||||
|
||||
void JsonFormatter::_safecat(const char *val, bool escape) {
|
||||
size_t len = (escape ? this->calcEscapedLength(val) : strlen(val)) + strlen(this->buff);
|
||||
if(escape) len += 2;
|
||||
if(len >= this->buffSize) {
|
||||
return;
|
||||
}
|
||||
if(escape) strcat(this->buff, "\"");
|
||||
if(escape) this->escapeString(val, &this->buff[strlen(this->buff)]);
|
||||
else strcat(this->buff, val);
|
||||
if(escape) strcat(this->buff, "\"");
|
||||
}
|
||||
void JsonFormatter::_appendNumber(const char *name) { this->appendElem(name); this->_safecat(this->_numbuff); }
|
||||
uint32_t JsonFormatter::calcEscapedLength(const char *raw) {
|
||||
uint32_t len = 0;
|
||||
for(size_t i = strlen(raw); i > 0; i--) {
|
||||
switch(raw[i]) {
|
||||
case '"':
|
||||
case '/':
|
||||
case '\b':
|
||||
case '\f':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t':
|
||||
case '\\':
|
||||
len += 2;
|
||||
break;
|
||||
default:
|
||||
len++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
void JsonFormatter::escapeString(const char *raw, char *escaped) {
|
||||
for(uint32_t i = 0; i < strlen(raw); i++) {
|
||||
switch(raw[i]) {
|
||||
case '"':
|
||||
strcat(escaped, "\\\"");
|
||||
break;
|
||||
case '/':
|
||||
strcat(escaped, "\\/");
|
||||
break;
|
||||
case '\b':
|
||||
strcat(escaped, "\\b");
|
||||
break;
|
||||
case '\f':
|
||||
strcat(escaped, "\\f");
|
||||
break;
|
||||
case '\n':
|
||||
strcat(escaped, "\\n");
|
||||
break;
|
||||
case '\r':
|
||||
strcat(escaped, "\\r");
|
||||
break;
|
||||
case '\t':
|
||||
strcat(escaped, "\\t");
|
||||
break;
|
||||
case '\\':
|
||||
strcat(escaped, "\\\\");
|
||||
break;
|
||||
default:
|
||||
size_t len = strlen(escaped);
|
||||
escaped[len] = raw[i];
|
||||
escaped[len+1] = 0x00;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
74
WResp.h
Normal file
74
WResp.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#include <WebServer.h>
|
||||
#include <WebSocketsServer.h>
|
||||
#include "Somfy.h"
|
||||
#ifndef wresp_h
|
||||
#define wresp_h
|
||||
|
||||
class JsonFormatter {
|
||||
protected:
|
||||
char *buff;
|
||||
size_t buffSize;
|
||||
bool _headersSent = false;
|
||||
uint8_t _objects = 0;
|
||||
uint8_t _arrays = 0;
|
||||
bool _nocomma = true;
|
||||
char _numbuff[25] = {0};
|
||||
virtual void _safecat(const char *val, bool escape = false);
|
||||
void _appendNumber(const char *name);
|
||||
public:
|
||||
void escapeString(const char *raw, char *escaped);
|
||||
uint32_t calcEscapedLength(const char *raw);
|
||||
void beginObject(const char *name = nullptr);
|
||||
void endObject();
|
||||
void beginArray(const char *name = nullptr);
|
||||
void endArray();
|
||||
void appendElem(const char *name = nullptr);
|
||||
|
||||
void addElem(const char* val);
|
||||
void addElem(float fval);
|
||||
void addElem(int8_t nval);
|
||||
void addElem(uint8_t nval);
|
||||
/*
|
||||
void addElem(int32_t nval);
|
||||
void addElem(int16_t nval);
|
||||
void addElem(uint16_t nval);
|
||||
void addElem(unsigned int nval);
|
||||
*/
|
||||
void addElem(int32_t lval);
|
||||
void addElem(uint32_t lval);
|
||||
void addElem(bool bval);
|
||||
|
||||
void addElem(const char* name, float fval);
|
||||
void addElem(const char* name, int8_t nval);
|
||||
void addElem(const char* name, uint8_t nval);
|
||||
/*
|
||||
void addElem(const char* name, int nval);
|
||||
void addElem(const char* name, int16_t nval);
|
||||
void addElem(const char* name, uint16_t nval);
|
||||
void addElem(const char* name, unsigned int nval);
|
||||
*/
|
||||
void addElem(const char* name, int32_t lval);
|
||||
void addElem(const char* name, uint32_t lval);
|
||||
void addElem(const char* name, bool bval);
|
||||
void addElem(const char *name, const char *val);
|
||||
};
|
||||
class JsonResponse : public JsonFormatter {
|
||||
protected:
|
||||
void _safecat(const char *val, bool escape = false) override;
|
||||
public:
|
||||
WebServer *server;
|
||||
void beginResponse(WebServer *server, char *buff, size_t buffSize);
|
||||
void endResponse();
|
||||
void send();
|
||||
};
|
||||
class JsonSockEvent : public JsonFormatter {
|
||||
protected:
|
||||
bool _closed = false;
|
||||
void _safecat(const char *val, bool escape = false) override;
|
||||
public:
|
||||
WebSocketsServer *server = nullptr;
|
||||
void beginEvent(WebSocketsServer *server, const char *evt, char *buff, size_t buffSize);
|
||||
void endEvent(uint8_t clientNum = 255);
|
||||
void closeEvent();
|
||||
};
|
||||
#endif
|
||||
9
Web.h
9
Web.h
|
|
@ -1,4 +1,5 @@
|
|||
#include <WebServer.h>
|
||||
#include "Somfy.h"
|
||||
#ifndef webserver_h
|
||||
#define webserver_h
|
||||
class Web {
|
||||
|
|
@ -41,9 +42,9 @@ class Web {
|
|||
bool createAPIPasswordToken(const IPAddress ipAddress, const char *username, const char *password, char *token);
|
||||
bool isAuthenticated(WebServer &server, bool cfg = false);
|
||||
|
||||
void chunkRoomsResponse(WebServer &server, const char *elem = nullptr);
|
||||
void chunkShadesResponse(WebServer &server, const char *elem = nullptr);
|
||||
void chunkGroupsResponse(WebServer &server, const char *elem = nullptr);
|
||||
//void chunkRoomsResponse(WebServer &server, const char *elem = nullptr);
|
||||
//void chunkShadesResponse(WebServer &server, const char *elem = nullptr);
|
||||
//void chunkGroupsResponse(WebServer &server, const char *elem = nullptr);
|
||||
//void chunkGroupResponse(WebServer &server, SomfyGroup *, const char *prefix = nullptr);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
BIN
data/apple-icon.png
Normal file
BIN
data/apple-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.5 KiB |
|
|
@ -1 +1 @@
|
|||
2.4.1
|
||||
2.4.7
|
||||
93
data/icon.svg
Normal file
93
data/icon.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 24 KiB |
|
|
@ -1494,4 +1494,49 @@ i.icss-bars {
|
|||
i.icss-bars:after {
|
||||
top: 0.36em;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
i.icss-hand {
|
||||
width: .6em;
|
||||
height: .5em;
|
||||
border-radius: .35em .3em .5em .5em;
|
||||
margin: .5em .1em 0 .21em;
|
||||
}
|
||||
|
||||
i.icss-hand:before {
|
||||
width: .1em;
|
||||
height: .55em;
|
||||
background: currentColor;
|
||||
left: .5em;
|
||||
bottom: .3em;
|
||||
border-radius: 80% / 20%;
|
||||
box-shadow: -.13em -.1em 0, -.265em -.15em 0, -.4em -.11em 0;
|
||||
}
|
||||
|
||||
i.icss-hand:after {
|
||||
width: .12em;
|
||||
height: .43em;
|
||||
background: currentColor;
|
||||
bottom: .25em;
|
||||
left: -.06em;
|
||||
border-radius: .04em;
|
||||
transform: rotate(-16deg);
|
||||
border-radius: .04em 70% .04em .04em / .04em 70% .04em .04em;
|
||||
}
|
||||
i.icss-bookmark {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
background-color: transparent;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
i.icss-bookmark:before {
|
||||
width: .5em;
|
||||
height: .8em;
|
||||
transform: translate(-50%, -50%);
|
||||
border: .25em solid currentColor;
|
||||
border-color: currentColor currentColor transparent currentColor;
|
||||
border-radius: .03em;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
}
|
||||
238
data/index.html
238
data/index.html
|
|
@ -3,11 +3,118 @@
|
|||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta charset="UTF-8">
|
||||
<link rel="stylesheet" href="main.css?v=2.4.1r" type="text/css" />
|
||||
<link rel="stylesheet" href="widgets.css?v=2.4.1r" type="text/css" />
|
||||
<link rel="stylesheet" href="icons.css?v=2.4.1r" type="text/css" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-title" content="ESPSomfy RTS App">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
|
||||
<link rel="stylesheet" href="main.css?v=2.4.7c" type="text/css" />
|
||||
<link rel="stylesheet" href="widgets.css?v=2.4.7c" type="text/css" />
|
||||
<link rel="stylesheet" href="icons.css?v=2.4.7c" type="text/css" />
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
<script type="text/javascript" src="index.js?v=2.4.1r"></script>
|
||||
|
||||
<!-- iPad retina icon -->
|
||||
<link href="apple-icon.png"
|
||||
sizes="152x152"
|
||||
rel="apple-touch-icon-precomposed">
|
||||
|
||||
<!-- iPad retina icon (iOS < 7) -->
|
||||
<link href="apple-icon.png"
|
||||
sizes="144x144"
|
||||
rel="apple-touch-icon-precomposed">
|
||||
|
||||
<!-- iPad non-retina icon -->
|
||||
<link href="apple-icon.png"
|
||||
sizes="76x76"
|
||||
rel="apple-touch-icon-precomposed">
|
||||
|
||||
<!-- iPad non-retina icon (iOS < 7) -->
|
||||
<link href="apple-icon.png"
|
||||
sizes="72x72"
|
||||
rel="apple-touch-icon-precomposed">
|
||||
|
||||
<!-- iPhone 6 Plus icon -->
|
||||
<link href="apple-icon.png"
|
||||
sizes="120x120"
|
||||
rel="apple-touch-icon-precomposed">
|
||||
|
||||
<!-- iPhone retina icon (iOS < 7) -->
|
||||
<link href="apple-icon.png"
|
||||
sizes="114x114"
|
||||
rel="apple-touch-icon-precomposed">
|
||||
|
||||
<!-- iPhone non-retina icon (iOS < 7) -->
|
||||
<link href="apple-icon.png"
|
||||
sizes="57x57"
|
||||
rel="apple-touch-icon-precomposed">
|
||||
|
||||
<link href="apple-icon.png"
|
||||
media="(device-width: 768px) and (device-height: 1024px)
|
||||
and (-webkit-device-pixel-ratio: 2)
|
||||
and (orientation: portrait)"
|
||||
rel="apple-touch-startup-image">
|
||||
|
||||
<!-- iPad retina landscape startup image -->
|
||||
<link href="apple-icon.png"
|
||||
media="(device-width: 768px) and (device-height: 1024px)
|
||||
and (-webkit-device-pixel-ratio: 2)
|
||||
and (orientation: landscape)"
|
||||
rel="apple-touch-startup-image">
|
||||
|
||||
<!-- iPad non-retina portrait startup image -->
|
||||
<link href="apple-icon.png"
|
||||
media="(device-width: 768px) and (device-height: 1024px)
|
||||
and (-webkit-device-pixel-ratio: 1)
|
||||
and (orientation: portrait)"
|
||||
rel="apple-touch-startup-image">
|
||||
|
||||
<!-- iPad non-retina landscape startup image -->
|
||||
<link href="apple-icon.png"
|
||||
media="(device-width: 768px) and (device-height: 1024px)
|
||||
and (-webkit-device-pixel-ratio: 1)
|
||||
and (orientation: landscape)"
|
||||
rel="apple-touch-startup-image">
|
||||
|
||||
<!-- iPhone 6 Plus portrait startup image -->
|
||||
<link href="apple-icon.png"
|
||||
media="(device-width: 414px) and (device-height: 736px)
|
||||
and (-webkit-device-pixel-ratio: 3)
|
||||
and (orientation: portrait)"
|
||||
rel="apple-touch-startup-image">
|
||||
|
||||
<!-- iPhone 6 Plus landscape startup image -->
|
||||
<link href="apple-icon.png"
|
||||
media="(device-width: 414px) and (device-height: 736px)
|
||||
and (-webkit-device-pixel-ratio: 3)
|
||||
and (orientation: landscape)"
|
||||
rel="apple-touch-startup-image">
|
||||
|
||||
<!-- iPhone 6 startup image -->
|
||||
<link href="apple-icon.png"
|
||||
media="(device-width: 375px) and (device-height: 667px)
|
||||
and (-webkit-device-pixel-ratio: 2)"
|
||||
rel="apple-touch-startup-image">
|
||||
|
||||
<!-- iPhone 5 startup image -->
|
||||
<link href="apple-icon.png"
|
||||
media="(device-width: 320px) and (device-height: 568px)
|
||||
and (-webkit-device-pixel-ratio: 2)"
|
||||
rel="apple-touch-startup-image">
|
||||
|
||||
<!-- iPhone < 5 retina startup image -->
|
||||
<link href="apple-icon.png"
|
||||
media="(device-width: 320px) and (device-height: 480px)
|
||||
and (-webkit-device-pixel-ratio: 2)"
|
||||
rel="apple-touch-startup-image">
|
||||
|
||||
<!-- iPhone < 5 non-retina startup image -->
|
||||
<link href="apple-icon.png"
|
||||
media="(device-width: 320px) and (device-height: 480px)
|
||||
and (-webkit-device-pixel-ratio: 1)"
|
||||
rel="apple-touch-startup-image">
|
||||
|
||||
|
||||
<script type="text/javascript" src="index.js?v=2.4.7c"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="divContainer" class="container main" data-auth="false">
|
||||
|
|
@ -53,7 +160,7 @@
|
|||
<input id="cbSsdpBroadcast" name="ssdpBroadcast" type="checkbox" data-bind="general.ssdpBroadcast" style="display:inline-block;" />
|
||||
<label for="cbSsdpBroadcast" style="display:inline-block;cursor:pointer;">Broadcast uPnP over SSDP</label>
|
||||
</div>
|
||||
<div class="field-group">
|
||||
<div class="field-group" style="margin-top:-12px;">
|
||||
<input id="cbCheckForUpdate" type="checkbox" data-bind="general.checkForUpdate" style="display:inline-block;" />
|
||||
<label for="cbCheckForUpdate" style="display:inline-block;cursor:pointer;">Auto Check for Updates</label>
|
||||
</div>
|
||||
|
|
@ -114,18 +221,32 @@
|
|||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="divFirmware" class="subtab-content" style="display:none;">
|
||||
<div style="font-size:17px;">
|
||||
<span style="text-align:right;display:inline-block;color:#00bcd4;width:127px;margin-top:-27px;">Hardware: </span>
|
||||
<span style="padding-left: 4px; display: inline-block;">ESP32<span id="spanHwVersion" style="text-transform:uppercase; text-align:left;width:120px;"></span></span>
|
||||
|
||||
<div id="divFirmware" class="subtab-content" style="display:none;padding-top:10px;">
|
||||
<div style="display:inline-block">
|
||||
<div style="font-size:17px;">
|
||||
<span style="text-align:right;display:inline-block;color:#00bcd4;width:127px;margin-top:-27px;">Hardware: </span>
|
||||
<span style="padding-left: 4px; display: inline-block;">ESP32<span id="spanHwVersion" style="text-transform:uppercase; text-align:left;width:120px;"></span></span>
|
||||
</div>
|
||||
<div style="font-size:17px;">
|
||||
<span style="text-align:right;display:inline-block;color:#00bcd4;width:127px;margin-top:-27px;">Firmware:</span>
|
||||
<span id="spanFwVersion" style="padding-left:4px;display:inline-block;text-align:left;width:120px;">v-.--</span>
|
||||
</div>
|
||||
<div style="font-size:17px;">
|
||||
<span style="text-align:right;display:inline-block;color:#00bcd4;width:127px;">Application:</span>
|
||||
<span id="spanAppVersion" style="padding-left:4px;display:inline-block;text-align:left;width:120px;">v-.--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="font-size:17px;">
|
||||
<span style="text-align:right;display:inline-block;color:#00bcd4;width:127px;margin-top:-27px;">Firmware:</span>
|
||||
<span id="spanFwVersion" style="padding-left:4px;display:inline-block;text-align:left;width:120px;">v-.--</span>
|
||||
</div>
|
||||
<div style="font-size:17px;">
|
||||
<span style="text-align:right;display:inline-block;color:#00bcd4;width:127px;">Application:</span>
|
||||
<span id="spanAppVersion" style="padding-left:4px;display:inline-block;text-align:left;width:120px;">v-.--</span>
|
||||
<div style="display:inline-block;font-size:12px;padding-top:10px;padding-left:37px;">
|
||||
<div style="color: #00bcd4;">Memory (bytes)</div>
|
||||
<div style="font-size:12px;display:inline-block;">
|
||||
<span style="text-align:right;display:inline-block;color:#00bcd4;">Free: </span>
|
||||
<span id="spanFreeMemory" style="text-align:right;width:120px;"></span>
|
||||
<span style="text-align:right;display:inline-block;color:#00bcd4;">Max: </span>
|
||||
<span id="spanMaxMemory" style="text-align:right;width:120px;"></span>
|
||||
<span style="text-align:right;display:inline-block;color:#00bcd4;">Min: </span>
|
||||
<span id="spanMinMemory" style="text-align:right;width:120px;"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="button-container">
|
||||
<button id="btnUpdateGithub" type="button" onclick="firmware.updateGithub();">
|
||||
|
|
@ -154,18 +275,25 @@
|
|||
<div id="divNetworkSettings" style="display:none;">
|
||||
<div class="subtab-container"><span class="selected" data-grpid="divNetAdapter">Adapter</span><span data-grpid="divDHCP">DHCP/Static IP</span><span data-grpid="divMQTT">MQTT</span></div>
|
||||
<div id="divNetAdapter" class="subtab-content">
|
||||
<div class="field-group" style="vertical-align:middle;color:#00bcd4;margin-top:-24px;margin-bottom:18px;">
|
||||
<div class="field-group" style="vertical-align:middle;color:#00bcd4;margin-top:-24px;">
|
||||
<input id="cbHardwired" name="hardwired" data-bind="ethernet.hardwired" type="checkbox" style="display:inline-block;" onclick="wifi.useEthernetClicked();" />
|
||||
<label for="cbHardwired" style="display:inline-block;cursor:pointer;">Use Ethernet</label>
|
||||
<div id="divRoaming" style="display:inline-block;padding-left:7px;">
|
||||
<input id="cbRoaming" name="roaming" data-bind="wifi.roaming" type="checkbox" style="display:inline-block;" />
|
||||
<label for="cbRoaming" style="display:inline-block;cursor:pointer;">Enable Roaming</label>
|
||||
</div>
|
||||
<div id="divFallbackWireless" style="display:inline-block;padding-left:7px;">
|
||||
<input id="cbFallbackWireless" name="fallbackwireless" data-bind="ethernet.wirelessFallback" type="checkbox" style="display:inline-block;" />
|
||||
<label for="cbFallbackWireless" style="display:inline-block;cursor:pointer;">Fallback to Wireless</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field-group" style="vertical-align:middle;color:#00bcd4;margin-top:-12px;margin-bottom:18px;">
|
||||
<div id="divHiddenSSID" style="display:inline-block;">
|
||||
<input id="cbHiddenSSID" data-bind="wifi.hidden" type="checkbox" style="display:inline-block;" onclick="wifi.hiddenSSIDClicked();" />
|
||||
<label for="cbHiddenSSID" style="display:inline-block;cursor:pointer;">Use Hidden SSID</label>
|
||||
</div>
|
||||
<div id="divRoaming" style="display:inline-block;padding-left:7px;">
|
||||
<input id="cbRoaming" name="roaming" data-bind="wifi.roaming" type="checkbox" style="display:inline-block;" />
|
||||
<label for="cbRoaming" style="display:inline-block;cursor:pointer;">Enable Roaming</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div id="divWiFiMode">
|
||||
<form method="post" action="/scan">
|
||||
<div id="divAps" data-lastloaded="0" style="border-radius:5px;border:solid 1px #00bcd4;margin-bottom:-10px;"></div>
|
||||
|
|
@ -221,7 +349,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div id="divDHCP" class="subtab-content" style="display:none;">
|
||||
<div style="margin-top:-14px;"><span style="color: #00bcd4;">IP Adddress:</span><span id="spanCurrentIP"></span></div>
|
||||
<div style="margin-top:-14px;"><span style="color: #00bcd4;">IP Address:</span><span id="spanCurrentIP"></span></div>
|
||||
<div class="field-group">
|
||||
<input id="cbUseDHCP" name="dhcp" type="checkbox" data-bind="ip.dhcp" style="display:inline-block;" onclick="wifi.onDHCPClicked(this);" checked="checked" />
|
||||
<label for="cbUseDHCP" style="display:inline-block;cursor:pointer;">Acquire IP Address automatically (DHCP)</label>
|
||||
|
|
@ -396,6 +524,10 @@
|
|||
<option value="11">Gate (left)</option>
|
||||
<option value="12">Gate (center)</option>
|
||||
<option value="13">Gate (right)</option>
|
||||
<option value="14">Gate (1-button left)</option>
|
||||
<option value="15">Gate (1-button center)</option>
|
||||
<option value="16">Gate (1-button right)</option>
|
||||
|
||||
</select>
|
||||
<label for="selShadeType">Type</label>
|
||||
</div>
|
||||
|
|
@ -488,6 +620,13 @@
|
|||
<label for="cbFlipPosition" style="display:block;font-size:1em;margin-top:0px;margin-left:7px;display:inline-block;">Invert Position (expressed in % of open)</label>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top:-10px;" id="divSimMy">
|
||||
<div class="field-group">
|
||||
<input id="cbSimMy" name="simMy" data-bind="simMy" type="checkbox" style="" />
|
||||
<label for="cbSimMy" style="display:block;font-size:1em;margin-top:0px;margin-left:7px;display:inline-block;">Simulate Favorite Position</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div classs="field-group" style="display:inline-block;">
|
||||
<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;">
|
||||
|
|
@ -647,11 +786,11 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="divVirtualRemote" style="display:none;" class="subtab-content">
|
||||
<div id="divVirtualRemote" style="display:none;" class="subtab-content" data-bitlength="56">
|
||||
<div class="field-group" style="margin-top:-18px;display:inline-block;width:100%;">
|
||||
<select id="selVRMotor" style="width:100%;">
|
||||
<select id="selVRMotor" style="width:100%;" onchange="document.getElementById('divVirtualRemote').setAttribute('data-bitlength', this.options[this.selectedIndex].getAttribute('data-bitlength'));">
|
||||
</select>
|
||||
<label for="selVRMotor">Select a Motor</label>
|
||||
<label for="selVRMotor">Select a Motor or Group</label>
|
||||
</div>
|
||||
<div class="vr-button vr-updownmy">
|
||||
<span>Remote Buttons</span>
|
||||
|
|
@ -661,12 +800,38 @@
|
|||
<div class="button-outline" data-cmd="down" onmousedown="somfy.sendVRCommand(this);" ontouchstart="somfy.sendVRCommand(this);"><i class="icss-somfy-down" style="margin-top:-4px;"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="vr-button vr-stop vr-80bit">
|
||||
<span>Stop</span>
|
||||
<div>
|
||||
<div class="button-outline toggle-button" style="width:127px;text-align:center;border-radius:33%;font-size:2em;padding:10px;" data-cmd="stop" onmousedown="somfy.sendVRCommand(this);" ontouchstart="somfy.sendVRCommand(this);"><i class="icss-hand" style=""></i></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="vr-button vr-updownmy">
|
||||
<span>Toggle Button</span>
|
||||
<div>
|
||||
<div class="button-outline toggle-button" style="width:127px;text-align:center;border-radius:33%;font-size:2em;padding:10px;" data-cmd="toggle" onmousedown="somfy.sendVRCommand(this);" ontouchstart="somfy.sendVRCommand(this);"><i class="icss-somfy-toggle" style="margin-top:-4px;"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="vr-button vr-updown vr-80bit">
|
||||
<span>Step</span>
|
||||
<div style="margin-right:7px;width:470px;font-size:.8em;">
|
||||
<input id="vrslidStepSize" name="stepSize" type="range" min="1" max="127" step="1" style="width:100%;" data-bind="stepSize" value="1" oninput="document.getElementById('vrspanStepSize').innerText = this.value;" />
|
||||
<div>
|
||||
<label style="color:#00bcd4;">Step Size:</label><span id="vrspanStepSize">1</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="button-outline" style="width:59px;text-align:center;border-radius:33%;font-size:2em;padding:10px;" data-cmd="StepUp" onmousedown="somfy.sendVRCommand(this);" ontouchstart="somfy.sendVRCommand(this);"><span></span><i class="icss-somfy-up" style="margin-top:4px;"></i></div>
|
||||
<div class="button-outline" style="width:59px;text-align:center;border-radius:33%;font-size:2em;padding:10px;" data-cmd="StepDown" onmousedown="somfy.sendVRCommand(this);" ontouchstart="somfy.sendVRCommand(this);"><span></span><i class="icss-somfy-down" style="margin-top:-4px;"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="vr-button vr-favorite vr-80bit">
|
||||
<span>Favorite</span>
|
||||
<div>
|
||||
<div class="button-outline toggle-button" style="width:127px;text-align:center;border-radius:33%;font-size:2em;padding:10px;" data-cmd="favorite" onmousedown="somfy.sendVRCommand(this);" ontouchstart="somfy.sendVRCommand(this);"><i class="icss-bookmark" style=""></i></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="vr-button vr-updown">
|
||||
<span>Up + Down</span>
|
||||
<div>
|
||||
|
|
@ -691,18 +856,6 @@
|
|||
<div class="button-outline" style="width:127px;text-align:center;border-radius:33%;font-size:2em;padding:10px;" data-cmd="MyDown" onmousedown="somfy.sendVRCommand(this);" ontouchstart="somfy.sendVRCommand(this);"><span>my</span><span> + </span><i class="icss-somfy-down"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="vr-button vr-updown">
|
||||
<span>Step Up</span>
|
||||
<div>
|
||||
<div class="button-outline" style="width:127px;text-align:center;border-radius:33%;font-size:2em;padding:10px;" data-cmd="StepUp" onmousedown="somfy.sendVRCommand(this);" ontouchstart="somfy.sendVRCommand(this);"><span>step </span><i class="icss-somfy-up"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="vr-button vr-updown">
|
||||
<span>Step Down</span>
|
||||
<div>
|
||||
<div class="button-outline" style="width:127px;text-align:center;border-radius:33%;font-size:2em;padding:10px;" data-cmd="StepDown" onmousedown="somfy.sendVRCommand(this);" ontouchstart="somfy.sendVRCommand(this);"><span>step </span><i class="icss-somfy-down"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="vr-button vr-updown">
|
||||
<span>Prog</span>
|
||||
<div>
|
||||
|
|
@ -710,15 +863,10 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="vr-button vr-updown">
|
||||
<span>Sun Flag On</span>
|
||||
<span>Sun Flag</span>
|
||||
<div>
|
||||
<div class="button-outline" style="width:127px;text-align:center;border-radius:33%;font-size:2em;padding:10px;" data-cmd="SunFlag" onmousedown="somfy.sendVRCommand(this);" ontouchstart="somfy.sendVRCommand(this);"><div class="button-sunflag" data-on="true" style="margin:0px;"><i class="icss-sun-c" style="background:white;"></i><i class="icss-sun-o" style="left:0px;color:white;"></i></div><span>on</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="vr-button vr-updown">
|
||||
<span>Sun Flag 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 class="button-outline" style="width: 59px; text-align: center; border-radius: 33%; font-size: 2em; padding: 10px; height: 52px;" data-cmd="SunFlag" onmousedown="somfy.sendVRCommand(this);" ontouchstart="somfy.sendVRCommand(this);"><div class="button-sunflag" data-on="true" style="margin:0px;margin-left:4px;"><i class="icss-sun-c" style="background:white;"></i><i class="icss-sun-o" style="left:0px;color:white;"></i></div></div>
|
||||
<div class="button-outline" style="width: 59px; text-align: center; border-radius: 33%; font-size: 2em; padding: 10px; height: 52px;" data-cmd="Flag" onmousedown="somfy.sendVRCommand(this);" ontouchstart="somfy.sendVRCommand(this);"><div class="button-sunflag" data-on="false" style="margin:0px;margin-left:4px;"><i class="icss-sun-c" style="background:transparent;"></i><i class="icss-sun-o" style="left:0px;color:white;"></i></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="vr-button">
|
||||
|
|
|
|||
145
data/index.js
145
data/index.js
|
|
@ -1,5 +1,6 @@
|
|||
//var hst = '192.168.1.208';
|
||||
var hst = '192.168.1.152';
|
||||
//var hst = '192.168.1.159';
|
||||
var _rooms = [{ roomId: 0, name: 'Home' }];
|
||||
|
||||
var errors = [
|
||||
|
|
@ -490,6 +491,9 @@ async function initSockets() {
|
|||
return value;
|
||||
});
|
||||
switch (eventName) {
|
||||
case 'memStatus':
|
||||
firmware.procMemoryStatus(msg);
|
||||
break;
|
||||
case 'updateProgress':
|
||||
firmware.procUpdateProgress(msg);
|
||||
break;
|
||||
|
|
@ -562,6 +566,8 @@ async function initSockets() {
|
|||
await wifi.loadNetwork();
|
||||
await somfy.loadSomfy();
|
||||
await mqtt.loadMQTT();
|
||||
if (ui.isConfigOpen()) socket.send('join:0');
|
||||
|
||||
//await general.init();
|
||||
//await somfy.init();
|
||||
//await mqtt.init();
|
||||
|
|
@ -1264,7 +1270,7 @@ var security = new Security();
|
|||
|
||||
class General {
|
||||
initialized = false;
|
||||
appVersion = 'v2.4.1';
|
||||
appVersion = 'v2.4.7';
|
||||
reloadApp = false;
|
||||
init() {
|
||||
if (this.initialized) return;
|
||||
|
|
@ -1597,12 +1603,13 @@ var general = new General();
|
|||
class Wifi {
|
||||
initialized = false;
|
||||
ethBoardTypes = [{ val: 0, label: 'Custom Config' },
|
||||
{ val: 1, label: 'WT32-ETH01', clk: 0, ct: 0, addr: 1, pwr: 16, mdc: 23, mdio: 18 },
|
||||
{ val: 2, label: 'Olimex ESP32-POE', clk: 3, ct: 0, addr: 0, pwr: 12, mdc: 23, mdio: 18 },
|
||||
{ val: 3, label: 'Olimex ESP32-EVB', clk: 0, ct: 0, addr: 0, pwr: -1, mdc: 23, mdio: 18 },
|
||||
{ val: 4, label: 'LILYGO T-Internet POE', clk: 3, ct: 0, addr: 0, pwr: 16, mdc: 23, mdio: 18 },
|
||||
{ val: 5, label: 'wESP32 v7+', clk: 0, ct: 2, addr: 0, pwr: -1, mdc: 16, mdio: 17 },
|
||||
{ val: 6, label: 'wESP32 < v7', clk: 0, ct: 0, addr: 0, pwr: -1, mdc: 16, mdio: 17 }
|
||||
{ val: 7, label: 'EST-PoE-32 - Everything Smart', clk: 3, ct: 0, addr: 0, pwr: 12, mdc: 23, mdio: 18 },
|
||||
{ val: 3, label: 'ESP32-EVB - Olimex', clk: 0, ct: 0, addr: 0, pwr: -1, mdc: 23, mdio: 18 },
|
||||
{ val: 2, label: 'ESP32-POE - Olimex', clk: 3, ct: 0, addr: 0, pwr: 12, mdc: 23, mdio: 18 },
|
||||
{ val: 4, label: 'T-Internet POE - LILYGO', clk: 3, ct: 0, addr: 0, pwr: 16, mdc: 23, mdio: 18 },
|
||||
{ val: 5, label: 'wESP32 v7+ - Silicognition', clk: 0, ct: 2, addr: 0, pwr: -1, mdc: 16, mdio: 17 },
|
||||
{ val: 6, label: 'wESP32 < v7 - Silicognition', clk: 0, ct: 0, addr: 0, pwr: -1, mdc: 16, mdio: 17 },
|
||||
{ val: 1, label: 'WT32-ETH01 - Wireless Tag', clk: 0, ct: 0, addr: 1, pwr: 16, mdc: 23, mdio: 18 }
|
||||
];
|
||||
ethClockModes = [{ val: 0, label: 'GPIO0 IN' }, { val: 1, label: 'GPIO0 OUT' }, { val: 2, label: 'GPIO16 OUT' }, { val: 3, label: 'GPIO17 OUT' }];
|
||||
ethPhyTypes = [{ val: 0, label: 'LAN8720' }, { val: 1, label: 'TLK110' }, { val: 2, label: 'RTL8201' }, { val: 3, label: 'DP83848' }, { val: 4, label: 'DM9051' }, { val: 5, label: 'KZ8081' }];
|
||||
|
|
@ -1669,6 +1676,7 @@ class Wifi {
|
|||
document.getElementById('cbHardwired').checked = settings.connType >= 2;
|
||||
document.getElementById('cbFallbackWireless').checked = settings.connType === 3;
|
||||
ui.toElement(pnl, settings);
|
||||
/*
|
||||
if (settings.connType >= 2) {
|
||||
document.getElementById('divWiFiMode').style.display = 'none';
|
||||
document.getElementById('divEthernetMode').style.display = '';
|
||||
|
|
@ -1681,10 +1689,13 @@ class Wifi {
|
|||
document.getElementById('divFallbackWireless').style.display = 'none';
|
||||
document.getElementById('divRoaming').style.display = 'inline-block';
|
||||
}
|
||||
*/
|
||||
ui.toElement(document.getElementById('divDHCP'), settings);
|
||||
document.getElementById('divETHSettings').style.display = settings.ethernet.boardType === 0 ? '' : 'none';
|
||||
document.getElementById('divStaticIP').style.display = settings.ip.dhcp ? 'none' : '';
|
||||
ui.toElement(document.getElementById('divDHCP'), settings);
|
||||
document.getElementById('spanCurrentIP').innerHTML = settings.ip.ip;
|
||||
this.useEthernetClicked();
|
||||
this.hiddenSSIDClicked();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -1695,6 +1706,12 @@ class Wifi {
|
|||
document.getElementById('divEthernetMode').style.display = useEthernet ? '' : 'none';
|
||||
document.getElementById('divFallbackWireless').style.display = useEthernet ? 'inline-block' : 'none';
|
||||
document.getElementById('divRoaming').style.display = useEthernet ? 'none' : 'inline-block';
|
||||
document.getElementById('divHiddenSSID').style.display = useEthernet ? 'none' : 'inline-block';
|
||||
}
|
||||
hiddenSSIDClicked() {
|
||||
let hidden = document.getElementById('cbHiddenSSID').checked;
|
||||
if (hidden) document.getElementById('cbRoaming').checked = false;
|
||||
document.getElementById('cbRoaming').disabled = hidden;
|
||||
}
|
||||
async loadAPs() {
|
||||
if (document.getElementById('btnScanAPs').classList.contains('disabled')) return;
|
||||
|
|
@ -1881,6 +1898,7 @@ class Wifi {
|
|||
});
|
||||
}
|
||||
procWifiStrength(strength) {
|
||||
//console.log(strength);
|
||||
let ssid = strength.ssid || strength.name;
|
||||
document.getElementById('spanNetworkSSID').innerHTML = !ssid || ssid === '' ? '-------------' : ssid;
|
||||
document.getElementById('spanNetworkChannel').innerHTML = isNaN(strength.channel) || strength.channel < 0 ? '--' : strength.channel;
|
||||
|
|
@ -1919,6 +1937,9 @@ class Somfy {
|
|||
{ 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 },
|
||||
{ type: 14, name: 'Gate (1-button left)', ico: 'icss-lgate', lift: true, fcmd: true, fpos: true },
|
||||
{ type: 15, name: 'Gate (1-button center)', ico: 'icss-cgate', lift: true, fcmd: true, fpos: true },
|
||||
{ type: 16, name: 'Gate (1-button right)', ico: 'icss-rgate', lift: true, fcmd: true, fpos: true },
|
||||
];
|
||||
init() {
|
||||
if (this.initialized) return;
|
||||
|
|
@ -2294,8 +2315,11 @@ class Somfy {
|
|||
opt.setAttribute('data-type', 'shade');
|
||||
opt.setAttribute('data-shadetype', shade.shadeType);
|
||||
opt.setAttribute('data-shadeid', shade.shadeId);
|
||||
opt.setAttribute('data-bitlength', shade.bitLength);
|
||||
optGroup.appendChild(opt);
|
||||
}
|
||||
let sopt = vrList.options[vrList.selectedIndex];
|
||||
document.getElementById('divVirtualRemote').setAttribute('data-bitlength', sopt ? sopt.getAttribute('data-bitlength') : 'none');
|
||||
document.getElementById('divShadeList').innerHTML = divCfg;
|
||||
let shadeControls = document.getElementById('divShadeControls');
|
||||
shadeControls.innerHTML = divCtl;
|
||||
|
|
@ -2582,12 +2606,15 @@ class Somfy {
|
|||
divCtl += `<span class="groupctl-name">${group.name}</span>`;
|
||||
divCtl += `<div class="groupctl-shades">`;
|
||||
if (typeof group.linkedShades !== 'undefined') {
|
||||
divCtl += `<label>Members:</label><span>${group.linkedShades.length}`;
|
||||
/*
|
||||
for (let j = 0; j < group.linkedShades.length; j++) {
|
||||
divCtl += '<span>';
|
||||
if (j !== 0) divCtl += ', ';
|
||||
divCtl += group.linkedShades[j].name;
|
||||
divCtl += '</span>';
|
||||
}
|
||||
*/
|
||||
}
|
||||
divCtl += '</div></div>';
|
||||
divCtl += `<div class="groupctl-buttons">`;
|
||||
|
|
@ -2601,9 +2628,13 @@ class Somfy {
|
|||
opt.setAttribute('data-address', group.remoteAddress);
|
||||
opt.setAttribute('data-type', 'group');
|
||||
opt.setAttribute('data-groupid', group.groupId);
|
||||
opt.setAttribute('data-bitlength', group.bitLength);
|
||||
optGroup.appendChild(opt);
|
||||
}
|
||||
}
|
||||
let sopt = vrList.options[vrList.selectedIndex];
|
||||
document.getElementById('divVirtualRemote').setAttribute('data-bitlength', sopt ? sopt.getAttribute('data-bitlength') : 'none');
|
||||
|
||||
document.getElementById('divGroupList').innerHTML = divCfg;
|
||||
let groupControls = document.getElementById('divGroupControls');
|
||||
groupControls.innerHTML = divCtl;
|
||||
|
|
@ -2765,8 +2796,8 @@ class Somfy {
|
|||
}
|
||||
pinMaps = [
|
||||
{ name: '', maxPins: 39, inputs: [0, 1, 6, 7, 8, 9, 10, 11, 37, 38], outputs: [3, 6, 7, 8, 9, 10, 11, 34, 35, 36, 37, 38, 39] },
|
||||
{ name: 's2', maxPins: 46, inputs: [0, 15, 16, 19, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 45], outputs: [0, 15, 16, 19, 20, 26, 27, 28, 29, 30, 31, 32, 45, 46]},
|
||||
{ name: 's3', maxPins: 48, inputs: [0, 19, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 39, 40, 41, 42, 43], outputs: [0, 19, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 39, 40, 41, 42, 43] },
|
||||
{ name: 's2', maxPins: 46, inputs: [0, 19, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 45], outputs: [0, 19, 20, 26, 27, 28, 29, 30, 31, 32, 45, 46]},
|
||||
{ name: 's3', maxPins: 48, inputs: [19, 20, 22, 23, 24, 25, 27, 28, 29, 30, 31, 32], outputs: [19, 20, 22, 23, 24, 25, 27, 28, 29, 30, 31, 32] },
|
||||
{ name: 'c3', maxPins: 21, inputs: [11, 12, 13, 14, 15, 16, 17, 18, 19, 20], outputs: [11, 12, 13, 14, 15, 16, 17, 21] }
|
||||
];
|
||||
|
||||
|
|
@ -2881,7 +2912,7 @@ class Somfy {
|
|||
proto = '-V';
|
||||
break;
|
||||
}
|
||||
let html = `<span>${frame.encKey}</span><span>${frame.address}</span><span>${frame.command}</span><span>${frame.rcode}</span><span>${frame.rssi}dBm</span><span>${frame.bits}${proto}</span><span>${fnFmtTime(frame.time)}</span><div class="frame-pulses">`;
|
||||
let html = `<span>${frame.encKey}</span><span>${frame.address}</span><span>${frame.command}<sup>${frame.stepSize ? frame.stepSize : ''}</sup></span><span>${frame.rcode}</span><span>${frame.rssi}dBm</span><span>${frame.bits}${proto}</span><span>${fnFmtTime(frame.time)}</span><div class="frame-pulses">`;
|
||||
for (let i = 0; i < frame.pulses.length; i++) {
|
||||
if (i !== 0) html += ',';
|
||||
html += `${frame.pulses[i]}`;
|
||||
|
|
@ -3229,6 +3260,9 @@ class Somfy {
|
|||
if (obj.proto === 8 || obj.proto === 9) {
|
||||
switch (obj.shadeType) {
|
||||
case 5: // Garage 1-button
|
||||
case 14: // Gate left 1-button
|
||||
case 15: // Gate center 1-button
|
||||
case 16: // Gate right 1-button
|
||||
case 10: // Two button dry contact
|
||||
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.');
|
||||
|
|
@ -3668,31 +3702,80 @@ class Somfy {
|
|||
html += '<li>If the shade does not jog, press the prog button again until the shade jogs.</li>';
|
||||
html += '</ul>';
|
||||
html += `<div class="button-container">`;
|
||||
html += `<button id="btnSendUnpairing" type="button" style="padding-left:20px;padding-right:20px;display:inline-block;" onclick="somfy.sendCommand(${shadeId}, 'prog', 1);">Prog</button>`;
|
||||
html += `<button id="btnSendUnpairing" type="button" style="padding-left:20px;padding-right:20px;display:inline-block;">Prog</button>`;
|
||||
html += `<button id="btnMarkPaired" type="button" style="padding-left:20px;padding-right:20px;display:inline-block;" onclick="somfy.setPaired(${shadeId}, false);">Shade Unpaired</button>`;
|
||||
html += `<button id="btnStopUnpairing" type="button" style="padding-left:20px;padding-right:20px;display:inline-block" onclick="document.getElementById('divPairing').remove();">Close</button>`;
|
||||
html += `</div>`;
|
||||
div.innerHTML = html;
|
||||
let fnRepeatProg = (err, shade) => {
|
||||
if (this.btnTimer) {
|
||||
clearTimeout(this.btnTimer);
|
||||
this.btnTimer = null;
|
||||
}
|
||||
if (err) return;
|
||||
if (mouseDown) {
|
||||
somfy.sendCommandRepeat(shadeId, 'prog', null, fnRepeatProg);
|
||||
}
|
||||
}
|
||||
document.getElementById('somfyShade').appendChild(div);
|
||||
let btn = document.getElementById('btnSendUnpairing');
|
||||
btn.addEventListener('mousedown', (event) => {
|
||||
console.log(this);
|
||||
console.log(event);
|
||||
console.log('mousedown');
|
||||
somfy.sendCommand(shadeId, 'prog', null, (err, shade) => { fnRepeatProg(err, shade); });
|
||||
}, true);
|
||||
btn.addEventListener('touchstart', (event) => {
|
||||
console.log(this);
|
||||
console.log(event);
|
||||
console.log('touchstart');
|
||||
somfy.sendCommand(shadeId, 'prog', null, (err, shade) => { fnRepeatProg(err, shade); });
|
||||
}, true);
|
||||
|
||||
return div;
|
||||
}
|
||||
sendCommand(shadeId, command, repeat, cb) {
|
||||
console.log(`Sending Shade command ${shadeId}-${command}`);
|
||||
let obj = { shadeId: shadeId };
|
||||
if (isNaN(parseInt(command, 10))) obj.command = command;
|
||||
else obj.target = parseInt(command, 10);
|
||||
if (typeof repeat === 'number') obj.repeat = parseInt(repeat);
|
||||
let obj = {};
|
||||
if (typeof shadeId.shadeId !== 'undefined') {
|
||||
obj = shadeId;
|
||||
cb = command;
|
||||
shadeId = obj.shadeId;
|
||||
repeat = obj.repeat;
|
||||
command = obj.command;
|
||||
}
|
||||
else {
|
||||
obj = { shadeId: shadeId };
|
||||
if (isNaN(parseInt(command, 10))) obj.command = command;
|
||||
else obj.target = parseInt(command, 10);
|
||||
if (typeof repeat === 'number') obj.repeat = parseInt(repeat);
|
||||
}
|
||||
putJSON('/shadeCommand', obj, (err, shade) => {
|
||||
if (typeof cb === 'function') cb(err, shade);
|
||||
});
|
||||
}
|
||||
sendCommandRepeat(shadeId, command, repeat, cb) {
|
||||
//console.log(`Sending Shade command ${shadeId}-${command}`);
|
||||
let obj = { shadeId: shadeId, command: command };
|
||||
if (typeof repeat === 'number') obj.repeat = parseInt(repeat);
|
||||
let obj = {};
|
||||
if (typeof shadeId.shadeId !== 'undefined') {
|
||||
obj = shadeId;
|
||||
cb = command;
|
||||
shadeId = obj.shadeId;
|
||||
repeat = obj.repeat;
|
||||
command = obj.command;
|
||||
}
|
||||
else {
|
||||
obj = { shadeId: shadeId, command: command };
|
||||
if (typeof repeat === 'number') obj.repeat = parseInt(repeat);
|
||||
}
|
||||
putJSON('/repeatCommand', obj, (err, shade) => {
|
||||
if (typeof cb === 'function') cb(err, shade);
|
||||
});
|
||||
|
||||
/*
|
||||
putJSON(`/repeatCommand?shadeId=${shadeId}&command=${command}`, null, (err, shade) => {
|
||||
if(typeof cb === 'function') cb(err, shade);
|
||||
});
|
||||
*/
|
||||
}
|
||||
sendGroupRepeat(groupId, command, repeat, cb) {
|
||||
let obj = { groupId: groupId, command: command };
|
||||
|
|
@ -3711,7 +3794,6 @@ class Somfy {
|
|||
cmd: el.getAttribute('data-cmd')
|
||||
};
|
||||
ui.fromElement(el.parentElement.parentElement, o);
|
||||
console.log(o);
|
||||
switch (o.type) {
|
||||
case 'shade':
|
||||
o.shadeId = parseInt(opt.getAttribute('data-shadeId'), 10);
|
||||
|
|
@ -3734,17 +3816,17 @@ class Somfy {
|
|||
else if (o.type === 'group')
|
||||
somfy.sendGroupRepeat(o.groupId, o.cmd, null, fnRepeatCommand);
|
||||
else
|
||||
somfy.sendCommandRepeat(o.shadeId, o.cmd, null, fnRepeatCommand);
|
||||
somfy.sendCommandRepeat(o, fnRepeatCommand);
|
||||
}
|
||||
}
|
||||
o.command = o.cmd;
|
||||
if (o.cmd === 'Sensor') {
|
||||
somfy.sendSetSensor(o);
|
||||
|
||||
}
|
||||
else if (o.type === 'group')
|
||||
somfy.sendGroupCommand(o.groupId, o.cmd, null, (err, group) => { fnRepeatCommand(err, group); });
|
||||
else
|
||||
somfy.sendCommand(o.shadeId, o.cmd, null, (err, shade) => { fnRepeatCommand(err, shade); });
|
||||
somfy.sendCommand(o, (err, shade) => { fnRepeatCommand(err, shade); });
|
||||
}
|
||||
sendSetSensor(obj, cb) {
|
||||
putJSON('/setSensor', obj, (err, device) => {
|
||||
|
|
@ -4099,6 +4181,9 @@ class Somfy {
|
|||
case 5:
|
||||
case 9:
|
||||
case 10:
|
||||
case 14:
|
||||
case 15:
|
||||
case 16:
|
||||
return;
|
||||
}
|
||||
let tiltType = parseInt(shade.getAttribute('data-tilt'), 10) || 0;
|
||||
|
|
@ -4190,7 +4275,7 @@ class Firmware {
|
|||
init() { this.initialized = true; }
|
||||
isMobile() {
|
||||
let agt = navigator.userAgent.toLowerCase();
|
||||
return /Android|iPhone|iPod|BlackBerry|BB|PlayBook|IEMobile|Windows Phone|Kindle|Silk|Opera Mini/i.test(navigator.userAgent);
|
||||
return /Android|iPhone|iPad|iPod|BlackBerry|BB|PlayBook|IEMobile|Windows Phone|Kindle|Silk|Opera Mini/i.test(navigator.userAgent);
|
||||
}
|
||||
async backup() {
|
||||
let overlay = ui.waitMessage(document.getElementById('divContainer'));
|
||||
|
|
@ -4292,6 +4377,18 @@ class Firmware {
|
|||
div.innerHTML = html;
|
||||
return div;
|
||||
}
|
||||
procMemoryStatus(mem) {
|
||||
console.log(mem);
|
||||
let sp = document.getElementById('spanFreeMemory');
|
||||
if (sp) sp.innerHTML = mem.free.fmt("#,##0");
|
||||
sp = document.getElementById('spanMaxMemory');
|
||||
if (sp) sp.innerHTML = mem.max.fmt('#,##0');
|
||||
sp = document.getElementById('spanMinMemory');
|
||||
if (sp) sp.innerHTML = mem.min.fmt('#,##0');
|
||||
|
||||
|
||||
}
|
||||
|
||||
procFwStatus(rel) {
|
||||
console.log(rel);
|
||||
let div = document.getElementById('divFirmwareUpdate');
|
||||
|
|
|
|||
|
|
@ -651,7 +651,10 @@ div.wait-overlay > .lds-roller {
|
|||
}
|
||||
.somfyGroupCtl .groupctl-shades {
|
||||
font-size:12px;
|
||||
margin-top:-3px;
|
||||
margin-top:0px;
|
||||
}
|
||||
.somfyGroupCtl .groupctl-shades > label {
|
||||
margin-right:3px;
|
||||
}
|
||||
.somfyGroupCtl .groupctl-name,
|
||||
.somfyShadeCtl .shadectl-name {
|
||||
|
|
@ -699,6 +702,12 @@ div.wait-overlay > .lds-roller {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
#divVirtualRemote[data-bitlength="56"] div.vr-button.vr-80bit {
|
||||
display:none;
|
||||
}
|
||||
#divVirtualRemote[data-bitlength="none"] div.vr-button {
|
||||
display:none;
|
||||
}
|
||||
.shade-positioner {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
|
|
@ -801,6 +810,7 @@ div.frame-header > span {
|
|||
}
|
||||
div.frame-row > span:nth-child(3),
|
||||
div.frame-header > span:nth-child(3) {
|
||||
white-space:nowrap;
|
||||
width: 80px;
|
||||
text-align:center;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,6 +150,9 @@
|
|||
.shadectl-buttons div.button-outline {
|
||||
display: inline-block;
|
||||
}
|
||||
.shadectl-buttons[data-shadetype="14"] > .cmd-button[data-cmd="sunflag"],
|
||||
.shadectl-buttons[data-shadetype="15"] > .cmd-button[data-cmd="sunflag"],
|
||||
.shadectl-buttons[data-shadetype="16"] > .cmd-button[data-cmd="sunflag"],
|
||||
.shadectl-buttons[data-shadetype="6"] > .cmd-button[data-cmd="sunflag"],
|
||||
.shadectl-buttons[data-shadetype="5"] > .cmd-button[data-cmd="sunflag"],
|
||||
.shadectl-buttons[data-shadetype="9"] > .cmd-button[data-cmd="sunflag"],
|
||||
|
|
@ -159,6 +162,15 @@
|
|||
.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="down"],
|
||||
.shadectl-buttons[data-shadetype="14"] > .button-outline[data-cmd="my"],
|
||||
.shadectl-buttons[data-shadetype="14"] > .button-outline[data-cmd="up"],
|
||||
.shadectl-buttons[data-shadetype="14"] > .button-outline[data-cmd="down"],
|
||||
.shadectl-buttons[data-shadetype="15"] > .button-outline[data-cmd="my"],
|
||||
.shadectl-buttons[data-shadetype="15"] > .button-outline[data-cmd="up"],
|
||||
.shadectl-buttons[data-shadetype="15"] > .button-outline[data-cmd="down"],
|
||||
.shadectl-buttons[data-shadetype="16"] > .button-outline[data-cmd="my"],
|
||||
.shadectl-buttons[data-shadetype="16"] > .button-outline[data-cmd="up"],
|
||||
.shadectl-buttons[data-shadetype="16"] > .button-outline[data-cmd="down"],
|
||||
.shadectl-buttons[data-shadetype="10"] > .button-outline[data-cmd="my"] {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -174,10 +186,13 @@
|
|||
.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"]):not([data-shadetype="14"]):not([data-shadetype="15"]):not([data-shadetype="16"]) > .button-outline[data-cmd="toggle"] {
|
||||
display: none;
|
||||
}
|
||||
.somfyShadeCtl[data-shadetype="5"] .shadectl-mypos,
|
||||
.somfyShadeCtl[data-shadetype="14"] .shadectl-mypos,
|
||||
.somfyShadeCtl[data-shadetype="15"] .shadectl-mypos,
|
||||
.somfyShadeCtl[data-shadetype="16"] .shadectl-mypos,
|
||||
.somfyShadeCtl[data-shadetype="9"] .shadectl-mypos,
|
||||
.somfyShadeCtl[data-tilt="3"] .shadectl-mypos .my-pos,
|
||||
.somfyShadeCtl:not([data-shadetype="1"]) .shadectl-mypos .my-pos-tilt,
|
||||
|
|
@ -239,12 +254,24 @@
|
|||
#somfyShade[data-proto="8"] #divGPIOMy,
|
||||
#somfyShade[data-bitlength="56"] #divStepSettings,
|
||||
#somfyShade[data-shadetype="5"] #divStepSettings,
|
||||
#somfyShade[data-shadetype="14"] #divStepSettings,
|
||||
#somfyShade[data-shadetype="15"] #divStepSettings,
|
||||
#somfyShade[data-shadetype="16"] #divStepSettings,
|
||||
#somfyShade[data-shadetype="6"] #divStepSettings {
|
||||
display: none;
|
||||
}
|
||||
#somfyShade[data-proto="9"][data-shadetype="5"] #divGPIOUp,
|
||||
#somfyShade[data-proto="9"][data-shadetype="5"] #divGPIOMy,
|
||||
#somfyShade[data-proto="8"][data-shadetype="5"] #divGPIOMy,
|
||||
#somfyShade[data-proto="9"][data-shadetype="14"] #divGPIOUp,
|
||||
#somfyShade[data-proto="9"][data-shadetype="14"] #divGPIOMy,
|
||||
#somfyShade[data-proto="8"][data-shadetype="14"] #divGPIOMy,
|
||||
#somfyShade[data-proto="9"][data-shadetype="15"] #divGPIOUp,
|
||||
#somfyShade[data-proto="9"][data-shadetype="15"] #divGPIOMy,
|
||||
#somfyShade[data-proto="8"][data-shadetype="15"] #divGPIOMy,
|
||||
#somfyShade[data-proto="9"][data-shadetype="16"] #divGPIOUp,
|
||||
#somfyShade[data-proto="9"][data-shadetype="16"] #divGPIOMy,
|
||||
#somfyShade[data-proto="8"][data-shadetype="16"] #divGPIOMy,
|
||||
#somfyShade[data-proto="9"][data-shadetype="9"] #divGPIOUp,
|
||||
#somfyShade[data-proto="9"][data-shadetype="9"] #divGPIOMy,
|
||||
#somfyShade[data-proto="8"][data-shadetype="9"] #divGPIOUp {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue