Browse Source

Merge branch 'dev' into sensors

Conflicts:
	code/espurna/data/index.html.gz
	code/espurna/static/index.html.gz.h
softuart
Xose Pérez 6 years ago
parent
commit
a0d1d7aa7f
29 changed files with 3161 additions and 3515 deletions
  1. +16
    -0
      .travis.yml
  2. +145
    -145
      CHANGELOG.md
  3. +25
    -11
      README.md
  4. +0
    -65
      code/.travis.yml
  5. +1
    -1
      code/espurna/config/all.h
  6. +1
    -0
      code/espurna/config/arduino.h
  7. +6
    -1
      code/espurna/config/general.h
  8. +29
    -0
      code/espurna/config/hardware.h
  9. BIN
      code/espurna/data/index.html.gz
  10. +1
    -1
      code/espurna/debug.ino
  11. +86
    -20
      code/espurna/homeassitant.ino
  12. +0
    -376
      code/espurna/libs/SSDPDevice.cpp
  13. +0
    -198
      code/espurna/libs/SSDPDevice.h
  14. +0
    -2
      code/espurna/libs/WebSocketIncommingBuffer.h
  15. +11
    -1
      code/espurna/light.ino
  16. +15
    -0
      code/espurna/migrate.ino
  17. +2
    -0
      code/espurna/mqtt.ino
  18. +3
    -2
      code/espurna/ota.ino
  19. +26
    -1
      code/espurna/relay.ino
  20. +16
    -9
      code/espurna/rfbridge.ino
  21. +13
    -6
      code/espurna/scheduler.ino
  22. +44
    -34
      code/espurna/sensor.ino
  23. +63
    -23
      code/espurna/ssdp.ino
  24. +2604
    -2602
      code/espurna/static/index.html.gz.h
  25. +7
    -0
      code/espurna/telnet.ino
  26. +13
    -9
      code/espurna/web.ino
  27. +3
    -4
      code/html/custom.js
  28. +7
    -4
      code/html/index.html
  29. +24
    -0
      code/platformio.ini

+ 16
- 0
.travis.yml View File

@ -0,0 +1,16 @@
language: python
python:
- "2.7"
sudo: false
cache:
directories:
- "~/.platformio"
install:
- pip install -U platformio
- cd code ; npm install --only=dev ; cd ..
script:
- cd code ; platformio run -e itead-sonoff-basic
branches:
only:
- master
- dev

+ 145
- 145
CHANGELOG.md View File

@ -6,56 +6,56 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [1.12.1] 2018-01-14 ## [1.12.1] 2018-01-14
### Added ### Added
- Option to perform a WiFi network scan from web UI - Option to perform a WiFi network scan from web UI
- Added hostname to web UI side menu (#404)
- Added hostname to web UI side menu ([#404](https://github.com/xoseperez/espurna/issues/404))
- Option to flash multiple devices with ESPurna OTA Manager - Option to flash multiple devices with ESPurna OTA Manager
### Fixed ### Fixed
- Fix web UI layout so signature does not overlay buttons (#396)
- Option to disable network scan and allow connecting to hidden SSID (#392, #399)
- Fix crash caused by a delay in UDP debugging code (#397)
- Fix memory leak in influxDB module (#410)
- Fix typos in web UI (#394, #421)
- Fix web UI layout so signature does not overlay buttons ([#396](https://github.com/xoseperez/espurna/issues/396))
- Option to disable network scan and allow connecting to hidden SSID ([#392](https://github.com/xoseperez/espurna/issues/392), [#399](https://github.com/xoseperez/espurna/issues/399))
- Fix crash caused by a delay in UDP debugging code ([#397](https://github.com/xoseperez/espurna/issues/397))
- Fix memory leak in influxDB module ([#410](https://github.com/xoseperez/espurna/issues/410))
- Fix typos in web UI ([#394](https://github.com/xoseperez/espurna/issues/394), [#421](https://github.com/xoseperez/espurna/issues/421))
### Changed ### Changed
- Updated to fauxmoESP 2.4.2 - Updated to fauxmoESP 2.4.2
- Changed default I2C GPIO for Wemos D1 (#420)
- Changed default I2C GPIO for Wemos D1 ([#420](https://github.com/xoseperez/espurna/issues/420))
- Some terminal commands have changed. See docs or type "help". - Some terminal commands have changed. See docs or type "help".
## [1.12.0] 2018-01-11 ## [1.12.0] 2018-01-11
### Added ### Added
- Scheduler (contributed by Stefano Cotterli, thank you!, #131)
- Scheduler (contributed by Stefano Cotterli, thank you!, [#131](https://github.com/xoseperez/espurna/issues/131))
- Added "wifi.scan" command to terminal - Added "wifi.scan" command to terminal
- Added ESPurna Switch board support - Added ESPurna Switch board support
- Added support for python3 in memanalyzer and ota scripts (thanks to Ryan Jarvis) - Added support for python3 in memanalyzer and ota scripts (thanks to Ryan Jarvis)
- Added BSSID, RSSI, channels and distance to web UI status tab - Added BSSID, RSSI, channels and distance to web UI status tab
- Added mDNS name resolving to MQTT, InfluxDB and NoFUSS modules (#129, disabled by default)
- Added mDNS name resolving to MQTT, InfluxDB and NoFUSS modules ([#129](https://github.com/xoseperez/espurna/issues/129), disabled by default)
### Fixed ### Fixed
- Update FauxmoESP library to 2.4.1, solves dependency issue (#388)
- Fixed hardware definition in Sonoff Basic and Dual R2 causing wrong relay state on boot (#365)
- Update FauxmoESP library to 2.4.1, solves dependency issue ([#388](https://github.com/xoseperez/espurna/issues/388))
- Fixed hardware definition in Sonoff Basic and Dual R2 causing wrong relay state on boot ([#365](https://github.com/xoseperez/espurna/issues/365))
### Changed ### Changed
- Removed auto-recursion check in Domoticz module (#379)
- Removed auto-recursion check in Domoticz module ([#379](https://github.com/xoseperez/espurna/issues/379))
- Rename terminal commands: reset.wifi to wifi.reset, reset.mqtt to mqtt.reset. - Rename terminal commands: reset.wifi to wifi.reset, reset.mqtt to mqtt.reset.
- Update JustWifi library to 1.1.6 (support for multiple SSIDs with the same name) - Update JustWifi library to 1.1.6 (support for multiple SSIDs with the same name)
- Changed the way Home Assistant module handles disabling auto-discovery (#383)
- Changed the way Home Assistant module handles disabling auto-discovery ([#383](https://github.com/xoseperez/espurna/issues/383))
## [1.11.4] 2018-01-09 ## [1.11.4] 2018-01-09
### Fixed ### Fixed
- Fix bug in RF Bridge when RF code contains the stop byte. Check overflow (#357)
- Fix bug in RF Bridge when RF code contains the stop byte. Check overflow ([#357](https://github.com/xoseperez/espurna/issues/357))
- Fixed typos in code and wiki (Thanks to Ryan Jarvis) - Fixed typos in code and wiki (Thanks to Ryan Jarvis)
- Fix bug in magnitude topic and units (#355)
- Fix bug in magnitude topic and units ([#355](https://github.com/xoseperez/espurna/issues/355))
### Added ### Added
- Small core build to allow two-step flashing method for big binaries - Small core build to allow two-step flashing method for big binaries
- Thingspeak support (#371, disabled by default)
- Color synchronization between lights using MQTT (#362)
- Support for Arilux AL-LC02 (#347)
- Thingspeak support ([#371](https://github.com/xoseperez/espurna/issues/371), disabled by default)
- Color synchronization between lights using MQTT ([#362](https://github.com/xoseperez/espurna/issues/362))
- Support for Arilux AL-LC02 ([#347](https://github.com/xoseperez/espurna/issues/347))
- Support for Tarpuna Shield for Wemos D1 - Support for Tarpuna Shield for Wemos D1
- Build option to disable password checking (#373)
- Option to report sensor address via MQTT (#377, I2C address, GPIO, Dallas address,...)
- Build option to disable password checking ([#373](https://github.com/xoseperez/espurna/issues/373))
- Option to report sensor address via MQTT ([#377](https://github.com/xoseperez/espurna/issues/377), I2C address, GPIO, Dallas address,...)
- Added binary size to memanalyzer script - Added binary size to memanalyzer script
- Option to specify custom client ID for MQTT connection (#368)
- Option to specify custom client ID for MQTT connection ([#368](https://github.com/xoseperez/espurna/issues/368))
- Cross-platform ESPurna OTA Manager implemented in python (untested) - Cross-platform ESPurna OTA Manager implemented in python (untested)
- Terminal command to get or set digital GPIO - Terminal command to get or set digital GPIO
@ -63,27 +63,27 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Using 2.3.0 for prebuilt binaries - Using 2.3.0 for prebuilt binaries
- Fix delay in DHT sensor - Fix delay in DHT sensor
- Allow MQTT keep alive value of up to 3600s - Allow MQTT keep alive value of up to 3600s
- Changed Sonoff 4CH Pro definitions to support built-in interlock mode (#333)
- Changed Sonoff 4CH Pro definitions to support built-in interlock mode ([#333](https://github.com/xoseperez/espurna/issues/333))
## [1.11.3] 2018-01-02 ## [1.11.3] 2018-01-02
### Fixed ### Fixed
- Fix uninitialized PWM channels bug (#356)
- Fix uninitialized PWM channels bug ([#356](https://github.com/xoseperez/espurna/issues/356))
### Added ### Added
- Added memory analyzer - Added memory analyzer
## [1.11.2] 2017-12-30 ## [1.11.2] 2017-12-30
### Fixed ### Fixed
- Fix my92xx and pwm references for Arduino IDE (#346)
- Fix SHT3X I2C sensor magnitude count (#337)
- Fix timing for DHT11 sensors (#294)
- Fix overflow in relayParsePayload with long MQTT messages (#344)
- Fix loading of Dallas and DHT sensors for Sonoff TH images (#352)
- Fix my92xx and pwm references for Arduino IDE ([#346](https://github.com/xoseperez/espurna/issues/346))
- Fix SHT3X I2C sensor magnitude count ([#337](https://github.com/xoseperez/espurna/issues/337))
- Fix timing for DHT11 sensors ([#294](https://github.com/xoseperez/espurna/issues/294))
- Fix overflow in relayParsePayload with long MQTT messages ([#344](https://github.com/xoseperez/espurna/issues/344))
- Fix loading of Dallas and DHT sensors for Sonoff TH images ([#352](https://github.com/xoseperez/espurna/issues/352))
- Subscribe to Domoticz MQTT topics only if Domotic< is enabled - Subscribe to Domoticz MQTT topics only if Domotic< is enabled
### Added ### Added
- Added option to change MQTT retain flag, QoS and keepalive time from webUI (#321)
- Added LED modes "always off" and "always on" (#348)
- Added option to change MQTT retain flag, QoS and keepalive time from webUI ([#321](https://github.com/xoseperez/espurna/issues/321))
- Added LED modes "always off" and "always on" ([#348](https://github.com/xoseperez/espurna/issues/348))
- Defined new ESPurna switch (no HLW8012 support & touch button ready) - Defined new ESPurna switch (no HLW8012 support & touch button ready)
### Changed ### Changed
@ -100,12 +100,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [1.11.0] 2017-12-28 ## [1.11.0] 2017-12-28
### Fixed ### Fixed
- Fixed Arduino IDE compilation issues (#330)
- Fixed Arduino IDE compilation issues ([#330](https://github.com/xoseperez/espurna/issues/330))
- Fixed issues with IE - Fixed issues with IE
- Fixed websocket auth issue with Safari (temporary) - Fixed websocket auth issue with Safari (temporary)
- Fixed MQTT group sync when different switches share same group - Fixed MQTT group sync when different switches share same group
- Fixed casting issue in buttonStore (#327)
- Fixed crash in InfluxDB initial heartbeat (#318)
- Fixed casting issue in buttonStore ([#327](https://github.com/xoseperez/espurna/issues/327))
- Fixed crash in InfluxDB initial heartbeat ([#318](https://github.com/xoseperez/espurna/issues/318))
- Fixed LED logic for ESPurna H08 board - Fixed LED logic for ESPurna H08 board
### Added ### Added
@ -116,54 +116,54 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Option to select sensor read interval and report interval from web UI - Option to select sensor read interval and report interval from web UI
- Itead RF Bridge - Itead RF Bridge
+ Match MQTT RFOUT codes to relays + Match MQTT RFOUT codes to relays
+ Force RFBridge to send messages even if switch is already in requested state (#324)
+ Force RFBridge to send messages even if switch is already in requested state ([#324](https://github.com/xoseperez/espurna/issues/324))
+ Implemented RFbridge message queue asynchronously + Implemented RFbridge message queue asynchronously
- Added option to load config via HTTP POST & reset (#335)
- Added option to define behaviour of the first LED between WIFI, MQTT, FIND-ME (#317)
- Added option to load config via HTTP POST & reset ([#335](https://github.com/xoseperez/espurna/issues/335))
- Added option to define behaviour of the first LED between WIFI, MQTT, FIND-ME ([#317](https://github.com/xoseperez/espurna/issues/317))
- Added HTML linter to gulp builder - Added HTML linter to gulp builder
- Added Help command on terminal (#338)
- Added preliminary support for SSDP (untested, disabled by default) (#282)
- Added Help command on terminal ([#338](https://github.com/xoseperez/espurna/issues/338))
- Added preliminary support for SSDP (untested, disabled by default) ([#282](https://github.com/xoseperez/espurna/issues/282))
- Reporting NTP datetime on MQTT heartbeat (thanks to Eldon R. Brown) - Reporting NTP datetime on MQTT heartbeat (thanks to Eldon R. Brown)
- Added version tracking and migration code - Added version tracking and migration code
- I2C and GPIO locking features - I2C and GPIO locking features
- Changed default button action for touch button devices (TOUCH and T1) (#327)
- Generic 8 channel board (#336)
- Changed default button action for touch button devices (TOUCH and T1) ([#327](https://github.com/xoseperez/espurna/issues/327))
- Generic 8 channel board ([#336](https://github.com/xoseperez/espurna/issues/336))
### Changed ### Changed
- Added more sensor data filters (Max, MobileAverage) - Added more sensor data filters (Max, MobileAverage)
- Changed max pulse time to 1h (#316)
- Renamed "reset" to "reboot" for clarity (#315)
- Changed max pulse time to 1h ([#316](https://github.com/xoseperez/espurna/issues/316))
- Renamed "reset" to "reboot" for clarity ([#315](https://github.com/xoseperez/espurna/issues/315))
- UI refactor - UI refactor
- Change apiRegister signature - Change apiRegister signature
## [1.10.1] 2017-12-05 ## [1.10.1] 2017-12-05
### Fixed ### Fixed
- Fix Sonoff RFBridge learn message from web UI (#287)
- Fix unstability in "one and just one" sync mode (#290)
- Fix unnecessary inclusion of my92xx library (#293)
- Limit the MQTT queue to 10 messages when "Use JSON payload" enabled (#296)
- Fix Sonoff RFBridge OFF button toggling switch (#303)
- Allow defining only ON or OFF codes in Sonoff RFBridge (#304)
- Disabled terminal support for Sonoff Dual (#310)
- Fix Sonoff RFBridge learn message from web UI ([#287](https://github.com/xoseperez/espurna/issues/287))
- Fix unstability in "one and just one" sync mode ([#290](https://github.com/xoseperez/espurna/issues/290))
- Fix unnecessary inclusion of my92xx library ([#293](https://github.com/xoseperez/espurna/issues/293))
- Limit the MQTT queue to 10 messages when "Use JSON payload" enabled ([#296](https://github.com/xoseperez/espurna/issues/296))
- Fix Sonoff RFBridge OFF button toggling switch ([#303](https://github.com/xoseperez/espurna/issues/303))
- Allow defining only ON or OFF codes in Sonoff RFBridge ([#304](https://github.com/xoseperez/espurna/issues/304))
- Disabled terminal support for Sonoff Dual ([#310](https://github.com/xoseperez/espurna/issues/310))
### Added ### Added
- Support for SI7021-based sensor by Itead Studio compatible with Sonoff TH (#216)
- Support for Sonoff Dual R2 (#286)
- MQTT group topics (sync two or more switches from different devices, #300)
- Support for SI7021-based sensor by Itead Studio compatible with Sonoff TH ([#216](https://github.com/xoseperez/espurna/issues/216))
- Support for Sonoff Dual R2 ([#286](https://github.com/xoseperez/espurna/issues/286))
- MQTT group topics (sync two or more switches from different devices, [#300](https://github.com/xoseperez/espurna/issues/300))
- Color transitions (enabled by default, can be disabled from web UI) - Color transitions (enabled by default, can be disabled from web UI)
- Option to disable MQTT support at build time - Option to disable MQTT support at build time
### Changed ### Changed
- Decreased PWM frequency for dimmer lights - Decreased PWM frequency for dimmer lights
- Changed password policy (#297)
- Changed password policy ([#297](https://github.com/xoseperez/espurna/issues/297))
## [1.10.0] 2017-11-26 ## [1.10.0] 2017-11-26
### Fixed ### Fixed
- Temperatures with 1 decimal resolution - Temperatures with 1 decimal resolution
- Issues with Sonoff B1 due to bad driver management (using my92xx library now) - Issues with Sonoff B1 due to bad driver management (using my92xx library now)
- Avoid recursive messages on Domoticz (#272)
- Avoid recursive messages on Domoticz ([#272](https://github.com/xoseperez/espurna/issues/272))
- Fixed Sonoff T1 configuration - Fixed Sonoff T1 configuration
- Simplify and fix web auth (#284)
- Simplify and fix web auth ([#284](https://github.com/xoseperez/espurna/issues/284))
- Fix Embedis custom parser - Fix Embedis custom parser
### Added ### Added
@ -171,16 +171,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Option to disable system check on build time - Option to disable system check on build time
- Power saving features (loopDelay and wifi sleep) - Power saving features (loopDelay and wifi sleep)
- Added Sonoff TH build environment - Added Sonoff TH build environment
- Send Home Assistant auto discover messages on connect (#279)
- Implemented Home Assistant availability topic (#280)
- Send Home Assistant auto discover messages on connect ([#279](https://github.com/xoseperez/espurna/issues/279))
- Implemented Home Assistant availability topic ([#280](https://github.com/xoseperez/espurna/issues/280))
- Update time, uptime and heap on webUI every heartbeat - Update time, uptime and heap on webUI every heartbeat
- Support for LLMNR and NetBIOS (#282)
- Support for LLMNR and NetBIOS ([#282](https://github.com/xoseperez/espurna/issues/282))
- Added I2C clean bus code - Added I2C clean bus code
- Added realm to auth challenge - Added realm to auth challenge
### Changed ### Changed
- Changed default hostname to "ESPURNA_XXXXXX" - Changed default hostname to "ESPURNA_XXXXXX"
- Binaries built against stable core (~40Kb less, #274)
- Binaries built against stable core (~40Kb less, [#274](https://github.com/xoseperez/espurna/issues/274))
- Enabled TERMINAL_SUPPORT for Sonoff Dual (only available via TELNET) - Enabled TERMINAL_SUPPORT for Sonoff Dual (only available via TELNET)
- Dinamically resize debug strings (now messages are not cropped) - Dinamically resize debug strings (now messages are not cropped)
- MQTT: unsubscribe to '#' before subscribing - MQTT: unsubscribe to '#' before subscribing
@ -194,7 +194,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Fixed bug in MY9291-based light bulbs at full brightness - Fixed bug in MY9291-based light bulbs at full brightness
### Added ### Added
- RFBridge: toggle when RF codes for ON and OFF are the same (#270)
- RFBridge: toggle when RF codes for ON and OFF are the same ([#270](https://github.com/xoseperez/espurna/issues/270))
- Support for HSV color schema (MQTT, API and webUI via a selector) - Support for HSV color schema (MQTT, API and webUI via a selector)
### Changed ### Changed
@ -202,9 +202,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [1.9.8] 2017-11-08 ## [1.9.8] 2017-11-08
### Fixed ### Fixed
- Removed dimmer lights flicker when saving to EEPROM (#191)
- Fixed low brightness in dimmer lights (#157)
- Fixed blank fields in energy (#258, #259)
- Removed dimmer lights flicker when saving to EEPROM ([#191](https://github.com/xoseperez/espurna/issues/191))
- Fixed low brightness in dimmer lights ([#157](https://github.com/xoseperez/espurna/issues/157))
- Fixed blank fields in energy ([#258](https://github.com/xoseperez/espurna/issues/258), [#259](https://github.com/xoseperez/espurna/issues/259))
- Fixed support for Arilux AL-LC06 - Fixed support for Arilux AL-LC06
- Updated fauxmoESP library with support for GetBinaryState actions - Updated fauxmoESP library with support for GetBinaryState actions
@ -223,42 +223,42 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [1.9.7] 2017-10-25 ## [1.9.7] 2017-10-25
### Fixed ### Fixed
- Fix Alexa interface switching on all lights (#256)
- Fix Alexa interface switching on all lights ([#256](https://github.com/xoseperez/espurna/issues/256))
## [1.9.6] 2017-10-23 ## [1.9.6] 2017-10-23
### Fixed ### Fixed
- Fix power report in Domoticz (#236)
- Fix Sonoff POW in AP mode (#241)
- Fix Home Automation auto-discovery (support for single relay switches and RGB lights, #235)
- Fix power report in Domoticz ([#236](https://github.com/xoseperez/espurna/issues/236))
- Fix Sonoff POW in AP mode ([#241](https://github.com/xoseperez/espurna/issues/241))
- Fix Home Automation auto-discovery (support for single relay switches and RGB lights, [#235](https://github.com/xoseperez/espurna/issues/235))
- Check WS authentication only on start event - Check WS authentication only on start event
### Added ### Added
- Support for 2.4.0 RC2 Arduino Core that fixes KRACK vulnerablity (pre-built images are compiled against this, #242)
- Support for 2.4.0 RC2 Arduino Core that fixes KRACK vulnerablity (pre-built images are compiled against this, [#242](https://github.com/xoseperez/espurna/issues/242))
- Support for ManCaveMade ESPLive board (thanks to Michael A. Cox) - Support for ManCaveMade ESPLive board (thanks to Michael A. Cox)
- Support for InterMIT Tech QuinLED 2.6 (thanks to Colin Shorts) - Support for InterMIT Tech QuinLED 2.6 (thanks to Colin Shorts)
- Support for Magic Home LED Controller 2.0 (thanks to users @gimi87 and @soif, #231)
- Support for Magic Home LED Controller 2.0 (thanks to users @gimi87 and @soif, [#231](https://github.com/xoseperez/espurna/issues/231))
- Support for Arilux AL-LC06 (thanks to Martijn Kruissen) - Support for Arilux AL-LC06 (thanks to Martijn Kruissen)
- Support for Xenon SM-PW702U Wifi boards (thanks to Joshua Harden, #212)
- Support for Authometion LYT8266 (testing, thanks to Joe Blellik, #213)
- Support for an external button for D1 Mini boards (thanks to user @PieBru, #239)
- Support for Xenon SM-PW702U Wifi boards (thanks to Joshua Harden, [#212](https://github.com/xoseperez/espurna/issues/212))
- Support for Authometion LYT8266 (testing, thanks to Joe Blellik, [#213](https://github.com/xoseperez/espurna/issues/213))
- Support for an external button for D1 Mini boards (thanks to user @PieBru, [#239](https://github.com/xoseperez/espurna/issues/239))
- Option to query relay status via MQTT or WS (thanks to Wesley Tuzza) - Option to query relay status via MQTT or WS (thanks to Wesley Tuzza)
- Automatically install dependencies for web interface builder (thanks to Hermann Kraus) - Automatically install dependencies for web interface builder (thanks to Hermann Kraus)
- Support for HSV and IR for Magic Home LED Controller (optional, disabled by default, thanks to Wesley Tuzza) - Support for HSV and IR for Magic Home LED Controller (optional, disabled by default, thanks to Wesley Tuzza)
- Added option to report DS18B20 temperatures based on changes (thanks to Michael A. Cox) - Added option to report DS18B20 temperatures based on changes (thanks to Michael A. Cox)
- Safer buffer handling for websocket data (thanks to Hermann Kraus & Björn Bergman) - Safer buffer handling for websocket data (thanks to Hermann Kraus & Björn Bergman)
- Updates HL8012 library with energy counting support (thanks to Hermann Kraus) - Updates HL8012 library with energy counting support (thanks to Hermann Kraus)
- Added option to disable light color persistence to avoid flickering (#191)
- Option to enable TELNET in STA mode from web UI (#203)
- Added option to disable light color persistence to avoid flickering ([#191](https://github.com/xoseperez/espurna/issues/191))
- Option to enable TELNET in STA mode from web UI ([#203](https://github.com/xoseperez/espurna/issues/203))
### Changed ### Changed
- Changed default MQTT base topic to "{identifier}" (no leading slashes, #208)
- Prevent reconnecting when in AP mode if a web session or a telnet session is active (#244)
- Web UI checks for pending changes before reset/reconnect options (#226)
- Changed default MQTT base topic to "{identifier}" (no leading slashes, [#208](https://github.com/xoseperez/espurna/issues/208))
- Prevent reconnecting when in AP mode if a web session or a telnet session is active ([#244](https://github.com/xoseperez/espurna/issues/244))
- Web UI checks for pending changes before reset/reconnect options ([#226](https://github.com/xoseperez/espurna/issues/226))
- Increase WIFI connect timeout and reconnect interval - Increase WIFI connect timeout and reconnect interval
## [1.9.5] 2017-09-28 ## [1.9.5] 2017-09-28
### Fixed ### Fixed
- Revert to JustWifi 1.1.4 (#228)
- Revert to JustWifi 1.1.4 ([#228](https://github.com/xoseperez/espurna/issues/228))
## [1.9.4] 2017-09-22 ## [1.9.4] 2017-09-22
### Added ### Added
@ -269,14 +269,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Support for powermeters based on ECH1560 IC (beta, untested) - Support for powermeters based on ECH1560 IC (beta, untested)
### Changed ### Changed
- Changed behaviour on MQTT connection failure (#215)
- Changed behaviour on MQTT connection failure ([#215](https://github.com/xoseperez/espurna/issues/215))
- Removed boot delay - Removed boot delay
- Refactor power modules - Refactor power modules
- Updated JustWifi library - Updated JustWifi library
### Fixed ### Fixed
- Set all esp8285 devices to use esp01_1m (#210, #225)
- Removed wifi gain option since it prevents some devices to connect (#204)
- Set all esp8285 devices to use esp01_1m ([#210](https://github.com/xoseperez/espurna/issues/210), [#225](https://github.com/xoseperez/espurna/issues/225))
- Removed wifi gain option since it prevents some devices to connect ([#204](https://github.com/xoseperez/espurna/issues/204))
## [1.9.3] 2017-09-04 ## [1.9.3] 2017-09-04
### Added ### Added
@ -289,13 +289,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Updated fauxmoESP library to 2.2.0 - Updated fauxmoESP library to 2.2.0
### Fixed ### Fixed
- Fix HLW8012 calibration (#194)
- Fix HLW8012 calibration ([#194](https://github.com/xoseperez/espurna/issues/194))
- Fix telnet dropping connection - Fix telnet dropping connection
- Fix WiFiSecureClient connection with PubSubClient (#64)
- Fix WiFiSecureClient connection with PubSubClient ([#64](https://github.com/xoseperez/espurna/issues/64))
## [1.9.2] 2017-08-31 ## [1.9.2] 2017-08-31
### Added ### Added
- System stability check (turns off everything except WIFI AP, OTA and telnet if there is a boot crash loop) (#196)
- System stability check (turns off everything except WIFI AP, OTA and telnet if there is a boot crash loop) ([#196](https://github.com/xoseperez/espurna/issues/196))
- Telnet support (enabled by default only on AP interface) - Telnet support (enabled by default only on AP interface)
- Option to set WiFi gain from web UI - Option to set WiFi gain from web UI
- Option to disable MQTT from web UI - Option to disable MQTT from web UI
@ -310,7 +310,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Changes in terminal commands ("reconnect" is now "reset.wifi", also new commands added) - Changes in terminal commands ("reconnect" is now "reset.wifi", also new commands added)
### Fixed ### Fixed
- Crash in settings saving (#190) and fixed UDP debug conditional build clauses
- Crash in settings saving ([#190](https://github.com/xoseperez/espurna/issues/190)) and fixed UDP debug conditional build clauses
## [1.9.1] 2017-08-27 ## [1.9.1] 2017-08-27
### Added ### Added
@ -324,44 +324,44 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Fixed ### Fixed
- Fixed build flags for DHT and DS18B20 in platformio.ini file - Fixed build flags for DHT and DS18B20 in platformio.ini file
- Fixed Itead Sonoff B1 by updating the my9291 library - Fixed Itead Sonoff B1 by updating the my9291 library
- Fixed light status on boot (#157)
- Fixed light status on boot ([#157](https://github.com/xoseperez/espurna/issues/157))
- Fixed CSS bug cause by a bad merge - Fixed CSS bug cause by a bad merge
## [1.9.0] 2017-08-25 ## [1.9.0] 2017-08-25
### Added ### Added
- Support for IteadStudio BN-SZ01 Ceiling Light (#132)
- Support for IteadStudio Sonoff RF Bridge (#173)
- Support for IteadStudio Sonoff 4CH Pro (#174)
- Support for IteadStudio BN-SZ01 Ceiling Light ([#132](https://github.com/xoseperez/espurna/issues/132))
- Support for IteadStudio Sonoff RF Bridge ([#173](https://github.com/xoseperez/espurna/issues/173))
- Support for IteadStudio Sonoff 4CH Pro ([#174](https://github.com/xoseperez/espurna/issues/174))
- Support for IteadStudio Sonoff B1 - Support for IteadStudio Sonoff B1
- Support for IteadStudio Sonoff LED - Support for IteadStudio Sonoff LED
- Support for IteadStudio Sonoff T1 wall switches (1, 2 and 4 channels) - Support for IteadStudio Sonoff T1 wall switches (1, 2 and 4 channels)
- Support for WiOn 50055 WiFi Wall Outlet & Tap - Support for WiOn 50055 WiFi Wall Outlet & Tap
- Support for EXS WiFi Relay v3.1 (and other future latching relay boards) (#152)
- TLS/SSL support for MQTT (caution: eats a lot of memory, do not use with web interface) (#64)
- Add support for delayed ON/OFF switches (#123, #161, #188)
- Added ON and OFF actions for button events (previously only TOGGLE available) (#182)
- Support for EXS WiFi Relay v3.1 (and other future latching relay boards) ([#152](https://github.com/xoseperez/espurna/issues/152))
- TLS/SSL support for MQTT (caution: eats a lot of memory, do not use with web interface) ([#64](https://github.com/xoseperez/espurna/issues/64))
- Add support for delayed ON/OFF switches ([#123](https://github.com/xoseperez/espurna/issues/123), [#161](https://github.com/xoseperez/espurna/issues/161), [#188](https://github.com/xoseperez/espurna/issues/188))
- Added ON and OFF actions for button events (previously only TOGGLE available) ([#182](https://github.com/xoseperez/espurna/issues/182))
- Sliders in web interface to control dimmer channels independently (also for brightness) - Sliders in web interface to control dimmer channels independently (also for brightness)
- Debug info about MQTT disconnect reason - Debug info about MQTT disconnect reason
### Changed ### Changed
- MQTT setters ending with "/set" by default - MQTT setters ending with "/set" by default
- Using DOUT flash mode on all devices (#167)
- Using DOUT flash mode on all devices ([#167](https://github.com/xoseperez/espurna/issues/167))
- Longer timeout for WiFi connection (better chances for Sonoff Basic to connect) - Longer timeout for WiFi connection (better chances for Sonoff Basic to connect)
- Changed MQTT topics for light devices (COLOR, BRIGHTNESS, MIRED, KELVIN, CHANNEL) (#144)
- Changed MQTT topics for light devices (COLOR, BRIGHTNESS, MIRED, KELVIN, CHANNEL) ([#144](https://github.com/xoseperez/espurna/issues/144))
- Changed the way light devices are defined (see LIGHT_PROVIDER_DIMMER) - Changed the way light devices are defined (see LIGHT_PROVIDER_DIMMER)
- Allow to disable color picker in web interface - Allow to disable color picker in web interface
- API returns processed values for HLW8012 sensor (not raw values anymore) (#176)
- API returns processed values for HLW8012 sensor (not raw values anymore) ([#176](https://github.com/xoseperez/espurna/issues/176))
- Major refactoring of settings - Major refactoring of settings
### Fixed ### Fixed
- Discard MQTT messages with empty payload (#185)
- Discard MQTT messages with empty payload ([#185](https://github.com/xoseperez/espurna/issues/185))
- Wifi connection issue (https://github.com/esp8266/Arduino/issues/2186) - Wifi connection issue (https://github.com/esp8266/Arduino/issues/2186)
- Alexa connection issue - Alexa connection issue
## [1.8.3] 2017-07-23 ## [1.8.3] 2017-07-23
### Added ### Added
- Issue #85 and #90. Option to report MQTT messages with JSON payloads
- Issue #170. Updated DebouceEvent library to allow disabling double click and get faster click responses
- Issue [#85](https://github.com/xoseperez/espurna/issues/85) and [#90](https://github.com/xoseperez/espurna/issues/90). Option to report MQTT messages with JSON payloads
- Issue [#170](https://github.com/xoseperez/espurna/issues/170). Updated DebouceEvent library to allow disabling double click and get faster click responses
- Using memory layout with no SPIFFS for 1Mb devices - Using memory layout with no SPIFFS for 1Mb devices
### Changed ### Changed
@ -369,8 +369,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Return times in ISO8601 format - Return times in ISO8601 format
### Fixed ### Fixed
- Issue #168. Added H801 to arduino.h file
- Issue #171. Fix corrupted will message
- Issue [#168](https://github.com/xoseperez/espurna/issues/168). Added H801 to arduino.h file
- Issue [#171](https://github.com/xoseperez/espurna/issues/171). Fix corrupted will message
## [1.8.2] 2017-07-16 ## [1.8.2] 2017-07-16
### Added ### Added
@ -379,45 +379,45 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Enable WIFI debug on hardware reset (button long click) - Enable WIFI debug on hardware reset (button long click)
### Changed ### Changed
- Issue #159. Allow decimals in relay pulse interval
- Issue [#159](https://github.com/xoseperez/espurna/issues/159). Allow decimals in relay pulse interval
- Updated HLW8012 library - Updated HLW8012 library
### Fixed ### Fixed
- Issue #148. Fix bug in conditional compilation check
- Issue #149. Using different pulse counters for each relay (thanks to Lauris Ieviņš)
- Issue #141. Limit relay pulse interval to 60s
- Issue [#148](https://github.com/xoseperez/espurna/issues/148). Fix bug in conditional compilation check
- Issue [#149](https://github.com/xoseperez/espurna/issues/149). Using different pulse counters for each relay (thanks to Lauris Ieviņš)
- Issue [#141](https://github.com/xoseperez/espurna/issues/141). Limit relay pulse interval to 60s
- Fixed units for apparent & reactive power (thanks to Lauris Ieviņš) - Fixed units for apparent & reactive power (thanks to Lauris Ieviņš)
- Fixed mDNS setup when using custom HTTP port for web interface - Fixed mDNS setup when using custom HTTP port for web interface
## [1.8.1] 2017-05-22 ## [1.8.1] 2017-05-22
### Fixed ### Fixed
- Issue #140. Fix no relay control bug in Sonoff Dual
- Issue [#140](https://github.com/xoseperez/espurna/issues/140). Fix no relay control bug in Sonoff Dual
## [1.8.0] 2017-05-21 ## [1.8.0] 2017-05-21
### Added ### Added
- Added gamma correction to RGB strips. Thanks to Chris Ward. - Added gamma correction to RGB strips. Thanks to Chris Ward.
- Added support for Huacanxing H801 WiFi LED Controller. Thanks to Minh Phuong Ly. - Added support for Huacanxing H801 WiFi LED Controller. Thanks to Minh Phuong Ly.
- Issue #138. Added NTP configuration from web interface
- Issue #128. Report color when booting and in heartbeat stream.
- Issue #126. Show NTP status in web interface.
- Issue [#138](https://github.com/xoseperez/espurna/issues/138). Added NTP configuration from web interface
- Issue [#128](https://github.com/xoseperez/espurna/issues/128). Report color when booting and in heartbeat stream.
- Issue [#126](https://github.com/xoseperez/espurna/issues/126). Show NTP status in web interface.
- Added filter limits on POW readings. - Added filter limits on POW readings.
- Added color temperature to RGB calculation. Thanks to Sacha Telgenhof. - Added color temperature to RGB calculation. Thanks to Sacha Telgenhof.
- Issue #120. Added relay flood protection. Thanks to Izik Dubnov.
- Issue [#120](https://github.com/xoseperez/espurna/issues/120). Added relay flood protection. Thanks to Izik Dubnov.
- Support for "#RRGGBB", "RRR,GGG,BBB" and "WWW" color formats. - Support for "#RRGGBB", "RRR,GGG,BBB" and "WWW" color formats.
- Issue #117. Added build date & time to web interface.
- Issue [#117](https://github.com/xoseperez/espurna/issues/117). Added build date & time to web interface.
### Fixed ### Fixed
- Fix MQTT_RELAY board conifugration. Thanks to Denis French. - Fix MQTT_RELAY board conifugration. Thanks to Denis French.
- Issue #125. Fix bug in relay status reading from EEPROM
- Issue #127. Fix button action in DUAL.
- Issue [#125](https://github.com/xoseperez/espurna/issues/125). Fix bug in relay status reading from EEPROM
- Issue [#127](https://github.com/xoseperez/espurna/issues/127). Fix button action in DUAL.
- Fix bug in Sonoff POW current reading. Thanks to Emmanuel Tatto. - Fix bug in Sonoff POW current reading. Thanks to Emmanuel Tatto.
- Minimizing my9291 flickering when booting. - Minimizing my9291 flickering when booting.
- Fix conditional flags in hardware.ino to support Arduino IDE. - Fix conditional flags in hardware.ino to support Arduino IDE.
## [1.7.1] 2017-03-28 ## [1.7.1] 2017-03-28
### Fixed ### Fixed
- Issue #113. Fix restoring color from EEPROM upon reboot
- Issue #113. Fix bug in API handlers
- Issue [#113](https://github.com/xoseperez/espurna/issues/113). Fix restoring color from EEPROM upon reboot
- Issue [#113](https://github.com/xoseperez/espurna/issues/113). Fix bug in API handlers
## [1.7.0] 2017-03-27 ## [1.7.0] 2017-03-27
### Added ### Added
@ -436,10 +436,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Prevent the SDK from saving WiFi configuration to flash - Prevent the SDK from saving WiFi configuration to flash
### Fixed ### Fixed
- Issue #113. Fix light bulb state to OFF in library prevented the bulb from turning on
- Issue #58. Added code to handle spurious readings
- Issue [#113](https://github.com/xoseperez/espurna/issues/113). Fix light bulb state to OFF in library prevented the bulb from turning on
- Issue [#58](https://github.com/xoseperez/espurna/issues/58). Added code to handle spurious readings
- Fix bug in HLW8012 calibration current parameter casting to int instead of float - Fix bug in HLW8012 calibration current parameter casting to int instead of float
- Issue #115. Removed local declaration of _mqttForward variable. Thanks to Paweł Fiedor
- Issue [#115](https://github.com/xoseperez/espurna/issues/115). Removed local declaration of _mqttForward variable. Thanks to Paweł Fiedor
- Fix MQTT will topic. Thanks to Asbjorn Tronhus - Fix MQTT will topic. Thanks to Asbjorn Tronhus
## [1.6.9] 2017-03-12 ## [1.6.9] 2017-03-12
@ -456,27 +456,27 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [1.6.8] 2017-03-01 ## [1.6.8] 2017-03-01
### Added ### Added
- Issue #85. Heartbeat reports now free heap, uptime and VCC every 5 minutes
- Issue [#85](https://github.com/xoseperez/espurna/issues/85). Heartbeat reports now free heap, uptime and VCC every 5 minutes
### Changed ### Changed
- Wait two minutes instead of one in AP mode before trying to reconnect to the router - Wait two minutes instead of one in AP mode before trying to reconnect to the router
- Issue #92. Debug log enabled by default in Arduino IDE
- Issue #91. Using AsyncMqttClient as default MQTT client again
- Issue [#92](https://github.com/xoseperez/espurna/issues/92). Debug log enabled by default in Arduino IDE
- Issue [#91](https://github.com/xoseperez/espurna/issues/91). Using AsyncMqttClient as default MQTT client again
### Fixed ### Fixed
- Report data from all sensors via websocket even if no MQTT connection - Report data from all sensors via websocket even if no MQTT connection
- Issue #92. Fix unknown reference in Arduino IDE
- Issue [#92](https://github.com/xoseperez/espurna/issues/92). Fix unknown reference in Arduino IDE
- Split data.h contents into 1k lines, otherwise Arduino IDE chokes on them - Split data.h contents into 1k lines, otherwise Arduino IDE chokes on them
- Discard empty MQTT topic while subscribing - Discard empty MQTT topic while subscribing
## [1.6.7] 2017-02-25 ## [1.6.7] 2017-02-25
### Added ### Added
- Support for OpenLight / AI-Light by AI-Thinker based on MY9291 LED driver - Support for OpenLight / AI-Light by AI-Thinker based on MY9291 LED driver
- Issue #87. Factory reset when physical button pressed for >10 seconds
- Issue [#87](https://github.com/xoseperez/espurna/issues/87). Factory reset when physical button pressed for >10 seconds
## [1.6.6] 2017-02-23 ## [1.6.6] 2017-02-23
### Fixed ### Fixed
- Issue #82. Fix critical bug on Sonoff Dual
- Issue [#82](https://github.com/xoseperez/espurna/issues/82). Fix critical bug on Sonoff Dual
## [1.6.5] 2017-02-22 ## [1.6.5] 2017-02-22
### Added ### Added
@ -488,8 +488,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Double & long clicks do nothing except for the first defined button - Double & long clicks do nothing except for the first defined button
### Fixed ### Fixed
- Issue #79. Fix bug in WiFi led notification & MQTT connectivity (using PubSubClient)
- Issue #73. Fix bug when building without Domoticz support
- Issue [#79](https://github.com/xoseperez/espurna/issues/79). Fix bug in WiFi led notification & MQTT connectivity (using PubSubClient)
- Issue [#73](https://github.com/xoseperez/espurna/issues/73). Fix bug when building without Domoticz support
- Fix Gulp tasks dependencies - Fix Gulp tasks dependencies
## [1.6.4] 2017-02-20 ## [1.6.4] 2017-02-20
@ -499,8 +499,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Support for PROGMEM debug messages (only wifi module has been changed) - Support for PROGMEM debug messages (only wifi module has been changed)
- Option to disable mDNS, enabled by default - Option to disable mDNS, enabled by default
- Show current web server port in debug log - Show current web server port in debug log
- Issue #75. Link relays to LEDs
- Issue #76. Using http://espurna.local when in AP mode
- Issue [#75](https://github.com/xoseperez/espurna/issues/75). Link relays to LEDs
- Issue [#76](https://github.com/xoseperez/espurna/issues/76). Using http://espurna.local when in AP mode
### Changed ### Changed
- Images and favicon is now embedded in the HTML - Images and favicon is now embedded in the HTML
@ -510,16 +510,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Fixed ### Fixed
- Memory leak in MQTT connection method - Memory leak in MQTT connection method
- Wait 60 seconds before retrying to connect when in AP mode - Wait 60 seconds before retrying to connect when in AP mode
- Issue #24 & #74. Update ESPAsyncTCP and ESPAsyncWebServer to latest GIT version that supports MSS defragmenting
- Issue #73. Fixes for windows machines
- Issue [#24](https://github.com/xoseperez/espurna/issues/24) & [#74](https://github.com/xoseperez/espurna/issues/74). Update ESPAsyncTCP and ESPAsyncWebServer to latest GIT version that supports MSS defragmenting
- Issue [#73](https://github.com/xoseperez/espurna/issues/73). Fixes for windows machines
### Removed ### Removed
- Captive portal removed, mDNS resolution for AP mode too - Captive portal removed, mDNS resolution for AP mode too
## [1.6.3] 2017-02-15 ## [1.6.3] 2017-02-15
### Added ### Added
- Issue #69. Temperature unit configuration from the web interface
- Issue #55. WebServer port configurable from the web interface, defaults to 80
- Issue [#69](https://github.com/xoseperez/espurna/issues/69). Temperature unit configuration from the web interface
- Issue [#55](https://github.com/xoseperez/espurna/issues/55). WebServer port configurable from the web interface, defaults to 80
- Expand network configuration when adding a new network - Expand network configuration when adding a new network
### Changed ### Changed
@ -528,7 +528,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Scan for strongest network only if more than 1 network configured - Scan for strongest network only if more than 1 network configured
### Fixed ### Fixed
- Issue #71. Added default values for netmask and DNS in web configuration
- Issue [#71](https://github.com/xoseperez/espurna/issues/71). Added default values for netmask and DNS in web configuration
- Fixed Itead 1CH self-locking/inching board definition - Fixed Itead 1CH self-locking/inching board definition
- Fixed PlatformIO environments for ESP8285 boards (4CH and Touch) - Fixed PlatformIO environments for ESP8285 boards (4CH and Touch)
@ -560,11 +560,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [1.5.4] 2017-02-03 ## [1.5.4] 2017-02-03
### Fixed ### Fixed
- Issue #50. Fix type bug in window variable when calculating energy for HLW8012 devices (Sonoff POW)
- Issue [#50](https://github.com/xoseperez/espurna/issues/50). Fix type bug in window variable when calculating energy for HLW8012 devices (Sonoff POW)
## [1.5.3] 2017-02-02 ## [1.5.3] 2017-02-02
### Fixed ### Fixed
- Issue #50 and #54. Fixed domoticz MQTT message format
- Issue [#50](https://github.com/xoseperez/espurna/issues/50) and [#54](https://github.com/xoseperez/espurna/issues/54). Fixed domoticz MQTT message format
### Added ### Added
- Energy calculation and aggregation. API entry points and MQTT messages. - Energy calculation and aggregation. API entry points and MQTT messages.
@ -597,9 +597,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Fixed ### Fixed
- MQTT will topic - MQTT will topic
- Crash with HLW812 interrupts while trying to create a WIFI connection - Crash with HLW812 interrupts while trying to create a WIFI connection
- Issue #20 Better inline documentation for Alexa and Domoticz default settings
- Issue #39 Fixed autoconnect issue with static IP (fixed in JustWifi library)
- Issue #41 Added password requirements to initial password change page
- Issue [#20](https://github.com/xoseperez/espurna/issues/20) Better inline documentation for Alexa and Domoticz default settings
- Issue [#39](https://github.com/xoseperez/espurna/issues/39) Fixed autoconnect issue with static IP (fixed in JustWifi library)
- Issue [#41](https://github.com/xoseperez/espurna/issues/41) Added password requirements to initial password change page
### Changed ### Changed
- Changed LED pattern for WIFI notifications (shorter pulses) - Changed LED pattern for WIFI notifications (shorter pulses)
@ -609,7 +609,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Adding current, voltage, apparent and reactive power reports to Sonoff POW (Web & MQTT) - Adding current, voltage, apparent and reactive power reports to Sonoff POW (Web & MQTT)
### Fixed ### Fixed
- Issue #35 Fixed frequent MQTT connection drops after WIFI reconnect
- Issue [#35](https://github.com/xoseperez/espurna/issues/35) Fixed frequent MQTT connection drops after WIFI reconnect
- Defer wifi disconnection from web interface to allow request to return - Defer wifi disconnection from web interface to allow request to return
### Changed ### Changed
@ -618,14 +618,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [1.4.3] 2017-01-11 ## [1.4.3] 2017-01-11
### Fixed ### Fixed
- Issue #6 Using forked Time library to prevent conflict with Arduino Core for ESP8266 time.h file in windows machines
- Issue [#6](https://github.com/xoseperez/espurna/issues/6) Using forked Time library to prevent conflict with Arduino Core for ESP8266 time.h file in windows machines
## [1.4.2] 2017-01-09 ## [1.4.2] 2017-01-09
### Added ### Added
- Support for inverse logic relays - Support for inverse logic relays
### Fixed ### Fixed
- Issue #31. Fixed error in relay identification from MQTT messages
- Issue [#31](https://github.com/xoseperez/espurna/issues/31). Fixed error in relay identification from MQTT messages
## [1.4.1] 2017-01-05 ## [1.4.1] 2017-01-05
### Added ### Added
@ -641,7 +641,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Support for static IP connections - Support for static IP connections
### Fixed ### Fixed
- Issue #16. Enforce minimum password strength in web interface
- Issue [#16](https://github.com/xoseperez/espurna/issues/16). Enforce minimum password strength in web interface
### Changed ### Changed
- Using default client_id provided by AsyncMqttClient - Using default client_id provided by AsyncMqttClient
@ -678,9 +678,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Skipping retained MQTT messages (configurable) - Skipping retained MQTT messages (configurable)
### Fixed ### Fixed
- Issue #11 Compile error when building sonoff-dual-debug
- Issue #14 MQTT Connection with Username an Password not working
- Issue #17 Moved static variable 'pending' to class variable
- Issue [#11](https://github.com/xoseperez/espurna/issues/11) Compile error when building sonoff-dual-debug
- Issue [#14](https://github.com/xoseperez/espurna/issues/14) MQTT Connection with Username an Password not working
- Issue [#17](https://github.com/xoseperez/espurna/issues/17) Moved static variable 'pending' to class variable
## [1.1.0] 2016-12-06 ## [1.1.0] 2016-12-06
### Added ### Added


+ 25
- 11
README.md View File

@ -1,19 +1,20 @@
# ESPurna Firmware # ESPurna Firmware
ESPurna ("spark" in Catalan) is a custom firmware for ESP8266 based smart switches.
It was originally developed with the **[IteadStudio Sonoff](https://www.itead.cc/sonoff-wifi-wireless-switch.html)** in mind but now it supports a growing number of ESP8266-based boards.
ESPurna ("spark" in Catalan) is a custom firmware for ESP8266 based smart switches and sensors.
It uses the Arduino Core for ESP8266 framework and a number of 3rd party libraries. It uses the Arduino Core for ESP8266 framework and a number of 3rd party libraries.
**Current Release Version is 1.12.1**
Read the [changes log](https://bitbucket.org/xoseperez/espurna/src/master/CHANGELOG.md).
[![version](https://badge.fury.io/gh/xoseperez%2Fespurna.svg)](CHANGELOG.md)
[![travis](https://travis-ci.org/xoseperez/espurna.svg?branch=master)](https://travis-ci.org/xoseperez/espurna)
[![license](https://img.shields.io/github/license/xoseperez/espurna.svg)](LICENSE)
[![donate](https://img.shields.io/badge/donate-PayPal-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=xose%2eperez%40gmail%2ecom&lc=US&no_note=0&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHostedGuest)
[![twitter](https://img.shields.io/twitter/follow/xoseperez.svg?style=social)](https://twitter.com/intent/follow?screen_name=xoseperez)
--- ---
## Features ## Features
* *KRACK* vulnerability free (when built against Arduino Core 2.4.0) * *KRACK* vulnerability free (when built against Arduino Core 2.4.0)
* Support for **multiple ESP8266-based boards** ([check list](https://bitbucket.org/xoseperez/espurna/wiki/Hardware))
* Support for **multiple ESP8266-based boards** ([check list](https://github.com/xoseperez/espurna/wiki/Hardware))
* Power saving options * Power saving options
* Wifi **AP Mode** or **STA mode** * Wifi **AP Mode** or **STA mode**
* Up to 5 different networks can be defined * Up to 5 different networks can be defined
@ -32,7 +33,7 @@ Read the [changes log](https://bitbucket.org/xoseperez/espurna/src/master/CHANGE
* Support for **MQTT groups** to sync switches between devices * Support for **MQTT groups** to sync switches between devices
* Support for **delayed ON/OFF** * Support for **delayed ON/OFF**
* **MQTT** enabled * **MQTT** enabled
* **SSL/TLS support** (not on regular builds, see #64)
* **SSL/TLS support** (not on regular builds, see [#64](https://github.com/xoseperez/espurna/issues/64))
* Switch on/off and toggle relays, group topics (sync relays between different devices) * Switch on/off and toggle relays, group topics (sync relays between different devices)
* Report button event notifications * Report button event notifications
* Enable/disable pulse mode * Enable/disable pulse mode
@ -114,6 +115,19 @@ Read the [changes log](https://bitbucket.org/xoseperez/espurna/src/master/CHANGE
## Notices ## Notices
---
> **2018-01-24**: This repository has been migrated from Bitbucket to GitHub. There were a number of reason to migrate the repository to GitHub. I like Bitbucket and I'm still using it for a lot of projects, but ESPurna has grown and its community as well. Some users have complain about Bitbucket not being enough community-focused. This change is mainly aimed to use a platform with greater acceptance on the open-source community and tools better suited to them (to you), like the possibility to contribute to the documentation in an easy way.
>
>What happened with all the info in Bitbucket? Well, most of it has been ported to GitHub, albeit with some quirks:
>
>* **Code** has, of course been migrated completely
>* **Issues** are all on GitHub already **but** all issues and comments show up as reported by me. The original reporter is referenced inside the body of the issue (or comment) with a link to his/her profile at Bitbucket and a link to his/her profile at GitHub if it happens to be the same username. I **suggest all reporters to subscribe to the issues they originally filed** (search for your BitBucket username to list them).
>* **Pull requests** historic has not been migrated. At the moment of the migration all pull-requests have been either merged or declined. Of course, those PR merged are in the code base, but the historic and comments in the PR pages will be lost.
>* **Documentation** it's on it way, first step will be to migrate existing wiki, maybe with a new TOC structure
>* **Watchers**, **Forks**, I'm afraid they are all gone. Visit the new repop home and click on the "Watch" button on the top right. And as you do it click also on the "Star" button too :)
>
>I apologize for any inconvenience this migration may have caused. I have decided to do it the hard way.
--- ---
> **2018-01-11**: As of current version (1.12.0) ESPurna is tested using Arduino Core 2.3.0 and it's meant to be built against that version. > **2018-01-11**: As of current version (1.12.0) ESPurna is tested using Arduino Core 2.3.0 and it's meant to be built against that version.
@ -121,7 +135,7 @@ Read the [changes log](https://bitbucket.org/xoseperez/espurna/src/master/CHANGE
> **2017-08-26**: since version 1.9.0 the default **MQTT topics for commands have changed**. They all now end with "/set". This means you will have to change your controller software (Node-RED or alike) to send messages to -for instance- "/home/living/light/relay/0/set". The device will publish its state in "/home/living/light/relay/0" like before. > **2017-08-26**: since version 1.9.0 the default **MQTT topics for commands have changed**. They all now end with "/set". This means you will have to change your controller software (Node-RED or alike) to send messages to -for instance- "/home/living/light/relay/0/set". The device will publish its state in "/home/living/light/relay/0" like before.
--- ---
> **2017-07-24**: Default flash layout changed in 1.8.3, as an unpredicted consequence devices will not be able to persist/retrieve configuration if flashed with 1.8.3 via **OTA** from **PlatformIO**. Please check issue #187.
> **2017-07-24**: Default flash layout changed in 1.8.3, as an unpredicted consequence devices will not be able to persist/retrieve configuration if flashed with 1.8.3 via **OTA** from **PlatformIO**. Please check issue [#187](https://github.com/xoseperez/espurna/issues/187).
--- ---
@ -135,15 +149,15 @@ There are several ways to contribute to ESpurna development. You can contribute
And of course you can always buy me a beer, coffee, tea,... via the donation button below. And of course you can always buy me a beer, coffee, tea,... via the donation button below.
[![Donate to ESPurna Project](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=xose%2eperez%40gmail%2ecom&lc=US&no_note=0&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHostedGuest)
[![Donate](https://img.shields.io/badge/donate-PayPal-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=xose%2eperez%40gmail%2ecom&lc=US&no_note=0&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHostedGuest)
## Documentation ## Documentation
For more information please refer to the [ESPurna Wiki](https://bitbucket.org/xoseperez/espurna/wiki/Home).
For more information please refer to the [ESPurna Wiki](https://github.com/xoseperez/espurna/wiki).
## Supported hardware ## Supported hardware
Here is the list of supported hardware. For more information please refer to the [ESPurna Wiki Hardware page](https://bitbucket.org/xoseperez/espurna/wiki/Hardware).
Here is the list of supported hardware. For more information please refer to the [ESPurna Wiki Hardware page](https://github.com/xoseperez/espurna/wiki/Hardware).
|||| ||||
|---|---|---| |---|---|---|


+ 0
- 65
code/.travis.yml View File

@ -1,65 +0,0 @@
# Continuous Integration (CI) is the practice, in software
# engineering, of merging all developer working copies with a shared mainline
# several times a day < http://docs.platformio.org/en/latest/ci/index.html >
#
# Documentation:
#
# * Travis CI Embedded Builds with PlatformIO
# < https://docs.travis-ci.com/user/integration/platformio/ >
#
# * PlatformIO integration with Travis CI
# < http://docs.platformio.org/en/latest/ci/travis.html >
#
# * User Guide for `platformio ci` command
# < http://docs.platformio.org/en/latest/userguide/cmd_ci.html >
#
#
# Please choice one of the following templates (proposed below) and uncomment
# it (remove "# " before each line) or use own configuration according to the
# Travis CI documentation (see above).
#
#
# Template #1: General project. Test it using existing `platformio.ini`.
#
language: python
python:
- "2.7"
sudo: false
cache:
directories:
- "~/.platformio"
install:
- pip install -U platformio
script:
- platformio run
#
# Template #2: The project is intended to by used as a library with examples
#
# language: python
# python:
# - "2.7"
#
# sudo: false
# cache:
# directories:
# - "~/.platformio"
#
# env:
# - PLATFORMIO_CI_SRC=path/to/test/file.c
# - PLATFORMIO_CI_SRC=examples/file.ino
# - PLATFORMIO_CI_SRC=path/to/test/directory
#
# install:
# - pip install -U platformio
#
# script:
# - platformio ci --lib="." --board=TYPE_1 --board=TYPE_2 --board=TYPE_N

+ 1
- 1
code/espurna/config/all.h View File

@ -3,7 +3,7 @@
the repo files you can either define USE_CUSTOM_H or remove the the repo files you can either define USE_CUSTOM_H or remove the
"#ifdef USE_CUSTOM_H" & "#endif" lines and add a "custom.h" "#ifdef USE_CUSTOM_H" & "#endif" lines and add a "custom.h"
file to this same folder. file to this same folder.
Check https://bitbucket.org/xoseperez/espurna/issues/104/general_customh
Check https://github.com/xoseperez/espurna/issues/104
for an example on how to use this file. for an example on how to use this file.
(Define USE_CUSTOM_H on commandline for platformio: (Define USE_CUSTOM_H on commandline for platformio:
export PLATFORMIO_BUILD_FLAGS="'-DUSE_CUSTOM_H'" ) export PLATFORMIO_BUILD_FLAGS="'-DUSE_CUSTOM_H'" )


+ 1
- 0
code/espurna/config/arduino.h View File

@ -59,6 +59,7 @@
//#define ARILUX_AL_LC11 //#define ARILUX_AL_LC11
//#define ARILUX_AL_LC02 //#define ARILUX_AL_LC02
//#define WEMOS_D1_TARPUNA_SHIELD //#define WEMOS_D1_TARPUNA_SHIELD
//#define MAGICHOME_LED_CONTROLLER_23
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
// Features (values below are non-default values) // Features (values below are non-default values)


+ 6
- 1
code/espurna/config/general.h View File

@ -416,7 +416,12 @@ PROGMEM const char* const custom_reset_string[] = {
#endif #endif
#ifndef SSDP_SUPPORT #ifndef SSDP_SUPPORT
#define SSDP_SUPPORT 0 // Publish device using SSDP protocol by default (3.32Kb)
#define SSDP_SUPPORT 1 // Publish device using SSDP protocol by default (4.59Kb)
#endif
#ifndef SSDP_DEVICE_TYPE
#define SSDP_DEVICE_TYPE "upnp:rootdevice"
//#define SSDP_DEVICE_TYPE "urn:schemas-upnp-org:device:BinaryLight:1"
#endif #endif
#if WEB_SUPPORT == 0 #if WEB_SUPPORT == 0


+ 29
- 0
code/espurna/config/hardware.h View File

@ -914,6 +914,35 @@
#define IR_PIN 4 #define IR_PIN 4
#define IR_BUTTON_SET 1 #define IR_BUTTON_SET 1
#elif defined(MAGICHOME_LED_CONTROLLER_23)
// Info
#define MANUFACTURER "MAGICHOME"
#define DEVICE "LED_CONTROLLER_23"
#define RELAY_PROVIDER RELAY_PROVIDER_LIGHT
#define LIGHT_PROVIDER LIGHT_PROVIDER_DIMMER
#define DUMMY_RELAY_COUNT 1
// LEDs
#define LED1_PIN 2
#define LED1_PIN_INVERSE 1
// Light
#define LIGHT_CHANNELS 4
#define LIGHT_CH1_PIN 12 // RED
#define LIGHT_CH2_PIN 5 // GREEN
#define LIGHT_CH3_PIN 13 // BLUE
#define LIGHT_CH4_PIN 15 // WHITE
#define LIGHT_CH1_INVERSE 0
#define LIGHT_CH2_INVERSE 0
#define LIGHT_CH3_INVERSE 0
#define LIGHT_CH4_INVERSE 0
// IR
#define IR_SUPPORT 1
#define IR_PIN 4
#define IR_BUTTON_SET 1
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// HUACANXING H801 & H802 // HUACANXING H801 & H802
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------


BIN
code/espurna/data/index.html.gz View File


+ 1
- 1
code/espurna/debug.ino View File

@ -27,7 +27,7 @@ void _debugSend(char * message) {
static bool add_timestamp = true; static bool add_timestamp = true;
char timestamp[10] = {0}; char timestamp[10] = {0};
if (add_timestamp) snprintf_P(timestamp, sizeof(timestamp), PSTR("[%06lu] "), millis() % 1000000); if (add_timestamp) snprintf_P(timestamp, sizeof(timestamp), PSTR("[%06lu] "), millis() % 1000000);
add_timestamp = (message[strlen(message)-1] == 10);
add_timestamp = (message[strlen(message)-1] == 10) || (message[strlen(message)-1] == 13);
#endif #endif
#if DEBUG_SERIAL_SUPPORT #if DEBUG_SERIAL_SUPPORT


+ 86
- 20
code/espurna/homeassitant.ino View File

@ -20,15 +20,47 @@ void _haWebSocketOnSend(JsonObject& root) {
root["haPrefix"] = getSetting("haPrefix", HOMEASSISTANT_PREFIX); root["haPrefix"] = getSetting("haPrefix", HOMEASSISTANT_PREFIX);
} }
void _haSend() {
#if SENSOR_SUPPORT
// Pending message to send?
if (!_haSendFlag) return;
void _haSendMagnitude(unsigned char i) {
// Are we connected?
if (!mqttConnected()) return;
String output;
DEBUG_MSG_P(PSTR("[HA] Sending autodiscovery MQTT message\n"));
if (_haEnabled) {
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
unsigned char type = magnitudeType(i);
root["device_class"] = "sensor";
root["name"] = getSetting("hostname") + String(" ") + magnitudeTopic(type);
root["state_topic"] = mqttTopic(magnitudeTopicIndex(i).c_str(), false);
root["unit_of_measurement"] = magnitudeUnits(type);
root.printTo(output);
}
String topic = getSetting("haPrefix", HOMEASSISTANT_PREFIX) +
"/sensor/" +
getSetting("hostname") + "_" + String(i) +
"/config";
mqttSendRaw(topic.c_str(), output.c_str());
mqttSend(MQTT_TOPIC_STATUS, MQTT_STATUS_ONLINE, true);
}
void _haSendMagnitudes() {
for (unsigned char i=0; i<magnitudeCount(); i++) {
_haSendMagnitude(i);
}
}
#endif
void _haSendSwitch(unsigned char i) {
String output; String output;
@ -37,12 +69,17 @@ void _haSend() {
DynamicJsonBuffer jsonBuffer; DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject(); JsonObject& root = jsonBuffer.createObject();
root["name"] = getSetting("hostname");
String name = getSetting("hostname");
if (relayCount() > 1) {
name += String(" switch #") + String(i);
}
root["name"] = name;
root["platform"] = "mqtt"; root["platform"] = "mqtt";
if (relayCount()) { if (relayCount()) {
root["state_topic"] = mqttTopic(MQTT_TOPIC_RELAY, 0, false);
root["command_topic"] = mqttTopic(MQTT_TOPIC_RELAY, 0, true);
root["state_topic"] = mqttTopic(MQTT_TOPIC_RELAY, i, false);
root["command_topic"] = mqttTopic(MQTT_TOPIC_RELAY, i, true);
root["payload_on"] = String("1"); root["payload_on"] = String("1");
root["payload_off"] = String("0"); root["payload_off"] = String("0");
root["availability_topic"] = mqttTopic(MQTT_TOPIC_STATUS, false); root["availability_topic"] = mqttTopic(MQTT_TOPIC_STATUS, false);
@ -52,17 +89,21 @@ void _haSend() {
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
if (lightHasColor()) {
root["brightness_state_topic"] = mqttTopic(MQTT_TOPIC_BRIGHTNESS, false);
root["brightness_command_topic"] = mqttTopic(MQTT_TOPIC_BRIGHTNESS, true);
root["rgb_state_topic"] = mqttTopic(MQTT_TOPIC_COLOR_RGB, false);
root["rgb_command_topic"] = mqttTopic(MQTT_TOPIC_COLOR_RGB, true);
root["color_temp_command_topic"] = mqttTopic(MQTT_TOPIC_MIRED, true);
}
if (i == 0) {
if (lightHasColor()) {
root["brightness_state_topic"] = mqttTopic(MQTT_TOPIC_BRIGHTNESS, false);
root["brightness_command_topic"] = mqttTopic(MQTT_TOPIC_BRIGHTNESS, true);
root["rgb_state_topic"] = mqttTopic(MQTT_TOPIC_COLOR_RGB, false);
root["rgb_command_topic"] = mqttTopic(MQTT_TOPIC_COLOR_RGB, true);
root["color_temp_command_topic"] = mqttTopic(MQTT_TOPIC_MIRED, true);
}
if (lightChannels() > 3) {
root["white_value_state_topic"] = mqttTopic(MQTT_TOPIC_CHANNEL, 3, false);
root["white_value_command_topic"] = mqttTopic(MQTT_TOPIC_CHANNEL, 3, true);
}
if (lightChannels() > 3) {
root["white_value_state_topic"] = mqttTopic(MQTT_TOPIC_CHANNEL, 3, false);
root["white_value_command_topic"] = mqttTopic(MQTT_TOPIC_CHANNEL, 3, true);
} }
#endif // LIGHT_PROVIDER != LIGHT_PROVIDER_NONE #endif // LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
@ -78,11 +119,36 @@ void _haSend() {
String topic = getSetting("haPrefix", HOMEASSISTANT_PREFIX) + String topic = getSetting("haPrefix", HOMEASSISTANT_PREFIX) +
"/" + component + "/" + component +
"/" + getSetting("hostname") +
"/" + getSetting("hostname") + "_" + String(i) +
"/config"; "/config";
mqttSendRaw(topic.c_str(), output.c_str()); mqttSendRaw(topic.c_str(), output.c_str());
mqttSend(MQTT_TOPIC_STATUS, MQTT_STATUS_ONLINE, true); mqttSend(MQTT_TOPIC_STATUS, MQTT_STATUS_ONLINE, true);
}
void _haSendSwitches() {
for (unsigned char i=0; i<relayCount(); i++) {
_haSendSwitch(i);
}
}
void _haSend() {
// Pending message to send?
if (!_haSendFlag) return;
// Are we connected?
if (!mqttConnected()) return;
DEBUG_MSG_P(PSTR("[HA] Sending autodiscovery MQTT message\n"));
// Send messages
_haSendSwitches();
#if SENSOR_SUPPORT
_haSendMagnitudes();
#endif
_haSendFlag = false; _haSendFlag = false;
} }


+ 0
- 376
code/espurna/libs/SSDPDevice.cpp View File

@ -1,376 +0,0 @@
#if SSDP_SUPPORT
#include "SSDPDevice.h"
#include "lwip/igmp.h"
SSDPDeviceClass::SSDPDeviceClass() :
m_server(0),
m_port(80),
m_ttl(SSDP_MULTICAST_TTL)
{
m_uuid[0] = '\0';
m_modelNumber[0] = '\0';
sprintf(m_deviceType, "urn:schemas-upnp-org:device:Basic:1");
m_friendlyName[0] = '\0';
m_presentationURL[0] = '\0';
m_serialNumber[0] = '\0';
m_modelName[0] = '\0';
m_modelURL[0] = '\0';
m_manufacturer[0] = '\0';
m_manufacturerURL[0] = '\0';
sprintf(m_schemaURL, "ssdp/schema.xml");
uint32_t chipId = ESP.getChipId();
sprintf(m_uuid, "38323636-4558-4dda-9188-cda0e6%02x%02x%02x",
(uint16_t)((chipId >> 16) & 0xff),
(uint16_t)((chipId >> 8) & 0xff),
(uint16_t)chipId & 0xff);
for (int i = 0; i < SSDP_QUEUE_SIZE; i++) {
m_queue[i].time = 0;
}
}
void SSDPDeviceClass::update() {
postNotifyUpdate();
}
bool SSDPDeviceClass::readLine(String &value) {
char buffer[65];
int bufferPos = 0;
while (1) {
int c = m_server->read();
if (c < 0) {
buffer[bufferPos] = '\0';
break;
}
if (c == '\r' && m_server->peek() == '\n') {
m_server->read();
buffer[bufferPos] = '\0';
break;
}
if (bufferPos < 64) {
buffer[bufferPos++] = c;
}
}
value = String(buffer);
return bufferPos > 0;
}
bool SSDPDeviceClass::readKeyValue(String &key, String &value) {
char buffer[65];
int bufferPos = 0;
while (1) {
int c = m_server->read();
if (c < 0) {
if (bufferPos == 0) return false;
buffer[bufferPos] = '\0';
break;
}
if (c == ':') {
buffer[bufferPos] = '\0';
while (m_server->peek() == ' ') m_server->read();
break;
}
else if (c == '\r' && m_server->peek() == '\n') {
m_server->read();
if (bufferPos == 0) return false;
buffer[bufferPos] = '\0';
key = String();
value = String(buffer);
return true;
}
if (bufferPos < 64) {
buffer[bufferPos++] = c;
}
}
key = String(buffer);
readLine(value);
return true;
}
void SSDPDeviceClass::postNotifyALive() {
unsigned long time = millis();
post(NOTIFY_ALIVE_INIT, ROOT_FOR_ALL, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 10);
post(NOTIFY_ALIVE_INIT, ROOT_BY_UUID, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 55);
post(NOTIFY_ALIVE_INIT, ROOT_BY_TYPE, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 80);
post(NOTIFY_ALIVE_INIT, ROOT_FOR_ALL, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 210);
post(NOTIFY_ALIVE_INIT, ROOT_BY_UUID, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 255);
post(NOTIFY_ALIVE_INIT, ROOT_BY_TYPE, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 280);
post(NOTIFY_ALIVE, ROOT_FOR_ALL, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 610);
post(NOTIFY_ALIVE, ROOT_BY_UUID, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 655);
post(NOTIFY_ALIVE, ROOT_BY_TYPE, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 680);
}
void SSDPDeviceClass::postNotifyUpdate() {
unsigned long time = millis();
post(NOTIFY_UPDATE, ROOT_FOR_ALL, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 10);
post(NOTIFY_UPDATE, ROOT_BY_UUID, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 55);
post(NOTIFY_UPDATE, ROOT_BY_TYPE, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 80);
}
void SSDPDeviceClass::postResponse(long mx) {
unsigned long time = millis();
unsigned long delay = random(0, mx) * 900L; // 1000 ms - 100 ms
IPAddress address = m_server->remoteIP();
uint16_t port = m_server->remotePort();
post(RESPONSE, ROOT_FOR_ALL, address, port, time + delay / 3);
post(RESPONSE, ROOT_BY_UUID, address, port, time + delay / 3 * 2);
post(RESPONSE, ROOT_BY_TYPE, address, port, time + delay);
}
void SSDPDeviceClass::postResponse(ssdp_udn_t udn, long mx) {
post(RESPONSE, udn, m_server->remoteIP(), m_server->remotePort(), millis() + random(0, mx) * 900L); // 1000 ms - 100 ms
}
void SSDPDeviceClass::post(ssdp_message_t type, ssdp_udn_t udn, IPAddress address, uint16_t port, unsigned long time) {
for (int i = 0; i < SSDP_QUEUE_SIZE; i++) {
if (m_queue[i].time == 0) {
m_queue[i].type = type;
m_queue[i].udn = udn;
m_queue[i].address = address;
m_queue[i].port = port;
m_queue[i].time = time;
break;
}
}
}
void SSDPDeviceClass::send(ssdp_send_parameters_t *parameters) {
char buffer[1460];
unsigned int ip = WiFi.localIP();
const char *typeTemplate;
const char *uri, *usn1, *usn2, *usn3;
switch (parameters->type) {
case NOTIFY_ALIVE_INIT:
case NOTIFY_ALIVE:
typeTemplate = SSDP_NOTIFY_ALIVE_TEMPLATE;
break;
case NOTIFY_UPDATE:
typeTemplate = SSDP_NOTIFY_UPDATE_TEMPLATE;
break;
default: // RESPONSE
typeTemplate = SSDP_RESPONSE_TEMPLATE;
break;
}
String uuid = "uuid:" + String(m_uuid);
switch (parameters->udn) {
case ROOT_FOR_ALL:
uri = "upnp:rootdevice";
usn1 = uuid.c_str();
usn2 = "::";
usn3 = "upnp:rootdevice";
break;
case ROOT_BY_UUID:
uri = uuid.c_str();
usn1 = uuid.c_str();
usn2 = "";
usn3 = "";
break;
case ROOT_BY_TYPE:
uri = m_deviceType;
usn1 = uuid.c_str();
usn2 = "::";
usn3 = m_deviceType;
break;
}
int len = snprintf_P(buffer, sizeof(buffer),
SSDP_PACKET_TEMPLATE, typeTemplate,
SSDP_INTERVAL, m_modelName, m_modelNumber, usn1, usn2, usn3, parameters->type == RESPONSE ? "ST" : "NT", uri,
IP2STR(&ip), m_port, m_schemaURL
);
if (parameters->address == SSDP_MULTICAST_ADDR) {
m_server->beginPacketMulticast(parameters->address, parameters->port, m_ttl);
}
else {
m_server->beginPacket(parameters->address, parameters->port);
}
m_server->write(buffer, len);
m_server->endPacket();
parameters->time = parameters->type == NOTIFY_ALIVE ? parameters->time + SSDP_INTERVAL * 900L : 0; // 1000 ms - 100 ms
}
String SSDPDeviceClass::schema() {
char buffer[1024];
uint32_t ip = WiFi.localIP();
snprintf(buffer, sizeof(buffer), SSDP_SCHEMA_TEMPLATE,
IP2STR(&ip), m_port, m_schemaURL,
m_deviceType,
m_friendlyName,
m_presentationURL,
m_serialNumber,
m_modelName,
m_modelNumber,
m_modelURL,
m_manufacturer,
m_manufacturerURL,
m_uuid
);
return String(buffer);
}
void SSDPDeviceClass::handleClient() {
IPAddress current = WiFi.localIP();
if (m_last != current) {
m_last = current;
for (int i = 0; i < SSDP_QUEUE_SIZE; i++) {
m_queue[i].time = 0;
}
if (current != INADDR_NONE) {
if (!m_server) m_server = new WiFiUDP();
m_server->beginMulticast(current, SSDP_MULTICAST_ADDR, SSDP_PORT);
postNotifyALive();
}
else if (m_server) {
m_server->stop();
}
}
if (m_server && m_server->parsePacket()) {
String value;
if (readLine(value) && value.equalsIgnoreCase("M-SEARCH * HTTP/1.1")) {
String key, st;
bool host = false, man = false;
long mx = 0;
while (readKeyValue(key, value)) {
if (key.equalsIgnoreCase("HOST") && value.equals("239.255.255.250:1900")) {
host = true;
}
else if (key.equalsIgnoreCase("MAN") && value.equals("\"ssdp:discover\"")) {
man = true;
}
else if (key.equalsIgnoreCase("ST")) {
st = value;
}
else if (key.equalsIgnoreCase("MX")) {
mx = value.toInt();
}
}
if (host && man && mx > 0) {
if (st.equals("ssdp:all")) {
postResponse(mx);
}
else if (st.equals("upnp:rootdevice")) {
postResponse(ROOT_FOR_ALL, mx);
}
else if (st.equals("uuid:" + String(m_uuid))) {
postResponse(ROOT_BY_UUID, mx);
}
else if (st.equals(m_deviceType)) {
postResponse(ROOT_BY_TYPE, mx);
}
}
}
m_server->flush();
}
else {
unsigned long time = millis();
for (int i = 0; i < SSDP_QUEUE_SIZE; i++) {
if (m_queue[i].time > 0 && m_queue[i].time < time) {
send(&m_queue[i]);
}
}
}
}
void SSDPDeviceClass::setSchemaURL(const char *url) {
strlcpy(m_schemaURL, url, sizeof(m_schemaURL));
}
void SSDPDeviceClass::setHTTPPort(uint16_t port) {
m_port = port;
}
void SSDPDeviceClass::setDeviceType(const char *deviceType) {
strlcpy(m_deviceType, deviceType, sizeof(m_deviceType));
}
void SSDPDeviceClass::setName(const char *name) {
strlcpy(m_friendlyName, name, sizeof(m_friendlyName));
}
void SSDPDeviceClass::setURL(const char *url) {
strlcpy(m_presentationURL, url, sizeof(m_presentationURL));
}
void SSDPDeviceClass::setSerialNumber(const char *serialNumber) {
strlcpy(m_serialNumber, serialNumber, sizeof(m_serialNumber));
}
void SSDPDeviceClass::setSerialNumber(const uint32_t serialNumber) {
snprintf(m_serialNumber, sizeof(uint32_t) * 2 + 1, "%08X", serialNumber);
}
void SSDPDeviceClass::setModelName(const char *name) {
strlcpy(m_modelName, name, sizeof(m_modelName));
}
void SSDPDeviceClass::setModelNumber(const char *num) {
strlcpy(m_modelNumber, num, sizeof(m_modelNumber));
}
void SSDPDeviceClass::setModelURL(const char *url) {
strlcpy(m_modelURL, url, sizeof(m_modelURL));
}
void SSDPDeviceClass::setManufacturer(const char *name) {
strlcpy(m_manufacturer, name, sizeof(m_manufacturer));
}
void SSDPDeviceClass::setManufacturerURL(const char *url) {
strlcpy(m_manufacturerURL, url, sizeof(m_manufacturerURL));
}
void SSDPDeviceClass::setTTL(const uint8_t ttl) {
m_ttl = ttl;
}
SSDPDeviceClass SSDPDevice;
#endif

+ 0
- 198
code/espurna/libs/SSDPDevice.h View File

@ -1,198 +0,0 @@
#if SSDP_SUPPORT // SSDP_SUPPORT
#ifndef _SSDPDEVICE_h
#define _SSDPDEVICE_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#define SSDP_INTERVAL 1200
#define SSDP_PORT 1900
//#define SSDP_METHOD_SIZE 10
//#define SSDP_URI_SIZE 2
//#define SSDP_BUFFER_SIZE 64
#define SSDP_MULTICAST_TTL 2
#define SSDP_QUEUE_SIZE 21
static const IPAddress SSDP_MULTICAST_ADDR(239, 255, 255, 250);
#define SSDP_UUID_SIZE 37
#define SSDP_SCHEMA_URL_SIZE 64
#define SSDP_DEVICE_TYPE_SIZE 64
#define SSDP_FRIENDLY_NAME_SIZE 64
#define SSDP_SERIAL_NUMBER_SIZE 32
#define SSDP_PRESENTATION_URL_SIZE 128
#define SSDP_MODEL_NAME_SIZE 64
#define SSDP_MODEL_URL_SIZE 128
#define SSDP_MODEL_VERSION_SIZE 32
#define SSDP_MANUFACTURER_SIZE 64
#define SSDP_MANUFACTURER_URL_SIZE 128
static const char* PROGMEM SSDP_RESPONSE_TEMPLATE =
"HTTP/1.1 200 OK\r\n"
"EXT:\r\n";
static const char* PROGMEM SSDP_NOTIFY_ALIVE_TEMPLATE =
"NOTIFY * HTTP/1.1\r\n"
"HOST: 239.255.255.250:1900\r\n"
"NTS: ssdp:alive\r\n";
static const char* PROGMEM SSDP_NOTIFY_UPDATE_TEMPLATE =
"NOTIFY * HTTP/1.1\r\n"
"HOST: 239.255.255.250:1900\r\n"
"NTS: ssdp:update\r\n";
static const char* PROGMEM SSDP_PACKET_TEMPLATE =
"%s" // _ssdp_response_template / _ssdp_notify_template
"CACHE-CONTROL: max-age=%u\r\n" // SSDP_INTERVAL
"SERVER: UPNP/1.1 %s/%s\r\n" // m_modelName, m_modelNumber
"USN: %s%s%s\r\n" // m_uuid
"%s: %s\r\n" // "NT" or "ST", m_deviceType
"LOCATION: http://%u.%u.%u.%u:%u/%s\r\n" // WiFi.localIP(), m_port, m_schemaURL
"\r\n";
static const char* PROGMEM SSDP_SCHEMA_TEMPLATE =
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/xml\r\n"
"Connection: close\r\n"
"Access-Control-Allow-Origin: *\r\n"
"\r\n"
"<?xml version=\"1.0\"?>"
"<root xmlns=\"urn:schemas-upnp-org:device-1-0\">"
"<specVersion>"
"<major>1</major>"
"<minor>0</minor>"
"</specVersion>"
"<URLBase>http://%u.%u.%u.%u:%u/%s</URLBase>" // WiFi.localIP(), _port
"<device>"
"<deviceType>%s</deviceType>"
"<friendlyName>%s</friendlyName>"
"<presentationURL>%s</presentationURL>"
"<serialNumber>%s</serialNumber>"
"<modelName>%s</modelName>"
"<modelNumber>%s</modelNumber>"
"<modelURL>%s</modelURL>"
"<manufacturer>%s</manufacturer>"
"<manufacturerURL>%s</manufacturerURL>"
"<UDN>uuid:%s</UDN>"
"</device>"
// "<iconList>"
// "<icon>"
// "<mimetype>image/png</mimetype>"
// "<height>48</height>"
// "<width>48</width>"
// "<depth>24</depth>"
// "<url>icon48.png</url>"
// "</icon>"
// "<icon>"
// "<mimetype>image/png</mimetype>"
// "<height>120</height>"
// "<width>120</width>"
// "<depth>24</depth>"
// "<url>icon120.png</url>"
// "</icon>"
// "</iconList>"
"</root>\r\n"
"\r\n";
typedef enum {
NOTIFY_ALIVE_INIT,
NOTIFY_ALIVE,
NOTIFY_UPDATE,
RESPONSE
} ssdp_message_t;
typedef enum {
ROOT_FOR_ALL,
ROOT_BY_UUID,
ROOT_BY_TYPE
} ssdp_udn_t;
typedef struct {
unsigned long time;
ssdp_message_t type;
ssdp_udn_t udn;
uint32_t address;
uint16_t port;
} ssdp_send_parameters_t;
class SSDPDeviceClass {
private:
WiFiUDP *m_server;
IPAddress m_last;
char m_schemaURL[SSDP_SCHEMA_URL_SIZE];
char m_uuid[SSDP_UUID_SIZE];
char m_deviceType[SSDP_DEVICE_TYPE_SIZE];
char m_friendlyName[SSDP_FRIENDLY_NAME_SIZE];
char m_serialNumber[SSDP_SERIAL_NUMBER_SIZE];
char m_presentationURL[SSDP_PRESENTATION_URL_SIZE];
char m_manufacturer[SSDP_MANUFACTURER_SIZE];
char m_manufacturerURL[SSDP_MANUFACTURER_URL_SIZE];
char m_modelName[SSDP_MODEL_NAME_SIZE];
char m_modelURL[SSDP_MODEL_URL_SIZE];
char m_modelNumber[SSDP_MODEL_VERSION_SIZE];
uint16_t m_port;
uint8_t m_ttl;
ssdp_send_parameters_t m_queue[SSDP_QUEUE_SIZE];
protected:
bool readLine(String &value);
bool readKeyValue(String &key, String &value);
void postNotifyALive();
void postNotifyUpdate();
void postResponse(long mx);
void postResponse(ssdp_udn_t udn, long mx);
void post(ssdp_message_t type, ssdp_udn_t udn, IPAddress address, uint16_t port, unsigned long time);
void send(ssdp_send_parameters_t *parameters);
public:
SSDPDeviceClass();
void update();
String schema();
void handleClient();
void setDeviceType(const String& deviceType) { setDeviceType(deviceType.c_str()); }
void setDeviceType(const char *deviceType);
void setName(const String& name) { setName(name.c_str()); }
void setName(const char *name);
void setURL(const String& url) { setURL(url.c_str()); }
void setURL(const char *url);
void setSchemaURL(const String& url) { setSchemaURL(url.c_str()); }
void setSchemaURL(const char *url);
void setSerialNumber(const String& serialNumber) { setSerialNumber(serialNumber.c_str()); }
void setSerialNumber(const char *serialNumber);
void setSerialNumber(const uint32_t serialNumber);
void setModelName(const String& name) { setModelName(name.c_str()); }
void setModelName(const char *name);
void setModelNumber(const String& num) { setModelNumber(num.c_str()); }
void setModelNumber(const char *num);
void setModelURL(const String& url) { setModelURL(url.c_str()); }
void setModelURL(const char *url);
void setManufacturer(const String& name) { setManufacturer(name.c_str()); }
void setManufacturer(const char *name);
void setManufacturerURL(const String& url) { setManufacturerURL(url.c_str()); }
void setManufacturerURL(const char *url);
void setHTTPPort(uint16_t port);
void setTTL(uint8_t ttl);
};
extern SSDPDeviceClass SSDPDevice;
#endif
#endif // SSDP_SUPPORT

+ 0
- 2
code/espurna/libs/WebSocketIncommingBuffer.h View File

@ -5,8 +5,6 @@ WebSocketIncommingBuffer
Code by Hermann Kraus (https://bitbucket.org/hermr2d2/) Code by Hermann Kraus (https://bitbucket.org/hermr2d2/)
and slightly modified. and slightly modified.
https://bitbucket.org/xoseperez/espurna/pull-requests/30/safer-buffer-handling-for-websocket-data
*/ */
#pragma once #pragma once


+ 11
- 1
code/espurna/light.ino View File

@ -27,6 +27,7 @@ Ticker _light_transition_ticker;
typedef struct { typedef struct {
unsigned char pin; unsigned char pin;
bool reverse; bool reverse;
bool state;
unsigned char value; // target or nominal value unsigned char value; // target or nominal value
unsigned char shadow; // represented value unsigned char shadow; // represented value
double current; // transition value double current; // transition value
@ -381,7 +382,7 @@ void _shadow() {
// Transitions // Transitions
unsigned char target; unsigned char target;
for (unsigned int i=0; i < _light_channel.size(); i++) { for (unsigned int i=0; i < _light_channel.size(); i++) {
if (_light_state) {
if (_light_state && _light_channel[i].state) {
target = _light_channel[i].value; target = _light_channel[i].value;
if ((_light_brightness < LIGHT_MAX_BRIGHTNESS) && _light_has_color && (i < 3)) { if ((_light_brightness < LIGHT_MAX_BRIGHTNESS) && _light_has_color && (i < 3)) {
target *= ((float) _light_brightness / LIGHT_MAX_BRIGHTNESS); target *= ((float) _light_brightness / LIGHT_MAX_BRIGHTNESS);
@ -659,6 +660,14 @@ void lightSave() {
} }
#endif #endif
void lightState(unsigned char i, bool state) {
_light_channel[i].state = state;
}
bool lightState(unsigned char i) {
return _light_channel[i].state;
}
void lightState(bool state) { void lightState(bool state) {
_light_state = state; _light_state = state;
} }
@ -1027,6 +1036,7 @@ void lightSetup() {
io_info[i][1] = getIOFunc(_light_channel[i].pin); io_info[i][1] = getIOFunc(_light_channel[i].pin);
io_info[i][2] = _light_channel[i].pin; io_info[i][2] = _light_channel[i].pin;
pinMode(_light_channel[i].pin, OUTPUT); pinMode(_light_channel[i].pin, OUTPUT);
_light_channel[i].state = true;
} }
pwm_init(LIGHT_MAX_PWM, pwm_duty_init, PWM_CHANNEL_NUM_MAX, io_info); pwm_init(LIGHT_MAX_PWM, pwm_duty_init, PWM_CHANNEL_NUM_MAX, io_info);
pwm_start(); pwm_start();


+ 15
- 0
code/espurna/migrate.ino View File

@ -698,6 +698,21 @@ void migrate() {
setSetting("chLogic", 3, 0); setSetting("chLogic", 3, 0);
setSetting("relays", 1); setSetting("relays", 1);
#elif defined(MAGICHOME_LED_CONTROLLER_23)
setSetting("board", 53);
setSetting("relayProvider", RELAY_PROVIDER_LIGHT);
setSetting("lightProvider", LIGHT_PROVIDER_DIMMER);
setSetting("chGPIO", 0, 12);
setSetting("chGPIO", 1, 5);
setSetting("chGPIO", 2, 13);
setSetting("chGPIO", 3, 15);
setSetting("chLogic", 0, 0);
setSetting("chLogic", 1, 0);
setSetting("chLogic", 2, 0);
setSetting("chLogic", 3, 0);
setSetting("relays", 1);
#else #else
// Allow users to define new settings without migration config // Allow users to define new settings without migration config


+ 2
- 0
code/espurna/mqtt.ino View File

@ -135,6 +135,7 @@ void _mqttConnect() {
DEBUG_MSG_P(PSTR("[MQTT] Client ID: %s\n"), _mqtt_clientid); DEBUG_MSG_P(PSTR("[MQTT] Client ID: %s\n"), _mqtt_clientid);
DEBUG_MSG_P(PSTR("[MQTT] QoS: %d\n"), _mqtt_qos); DEBUG_MSG_P(PSTR("[MQTT] QoS: %d\n"), _mqtt_qos);
DEBUG_MSG_P(PSTR("[MQTT] Retain flag: %d\n"), _mqtt_retain ? 1 : 0); DEBUG_MSG_P(PSTR("[MQTT] Retain flag: %d\n"), _mqtt_retain ? 1 : 0);
DEBUG_MSG_P(PSTR("[MQTT] Keepalive time: %ds\n"), _mqtt_keepalive);
DEBUG_MSG_P(PSTR("[MQTT] Will topic: %s\n"), _mqtt_will); DEBUG_MSG_P(PSTR("[MQTT] Will topic: %s\n"), _mqtt_will);
_mqtt.connect(); _mqtt.connect();
@ -192,6 +193,7 @@ void _mqttConnect() {
DEBUG_MSG_P(PSTR("[MQTT] Client ID: %s\n"), _mqtt_clientid); DEBUG_MSG_P(PSTR("[MQTT] Client ID: %s\n"), _mqtt_clientid);
DEBUG_MSG_P(PSTR("[MQTT] QoS: %d\n"), _mqtt_qos); DEBUG_MSG_P(PSTR("[MQTT] QoS: %d\n"), _mqtt_qos);
DEBUG_MSG_P(PSTR("[MQTT] Retain flag: %d\n"), _mqtt_retain ? 1 : 0); DEBUG_MSG_P(PSTR("[MQTT] Retain flag: %d\n"), _mqtt_retain ? 1 : 0);
DEBUG_MSG_P(PSTR("[MQTT] Keepalive time: %ds\n"), _mqtt_keepalive);
DEBUG_MSG_P(PSTR("[MQTT] Will topic: %s\n"), _mqtt_will); DEBUG_MSG_P(PSTR("[MQTT] Will topic: %s\n"), _mqtt_will);
} }


+ 3
- 2
code/espurna/ota.ino View File

@ -37,7 +37,8 @@ void otaSetup() {
}); });
ArduinoOTA.onEnd([]() { ArduinoOTA.onEnd([]() {
DEBUG_MSG_P(PSTR("\n[OTA] End\n"));
DEBUG_MSG_P(PSTR("\n"));
DEBUG_MSG_P(PSTR("[OTA] End\n"));
#if WEB_SUPPORT #if WEB_SUPPORT
wsSend_P(PSTR("{\"action\": \"reload\"}")); wsSend_P(PSTR("{\"action\": \"reload\"}"));
#endif #endif
@ -45,7 +46,7 @@ void otaSetup() {
}); });
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
DEBUG_MSG_P(PSTR("[OTA] Progress: %u%%%% \r"), (progress / (total / 100)));
DEBUG_MSG_P(PSTR("[OTA] Progress: %u%%\r"), (progress / (total / 100)));
}); });
ArduinoOTA.onError([](ota_error_t error) { ArduinoOTA.onError([](ota_error_t error) {


+ 26
- 1
code/espurna/relay.ino View File

@ -78,8 +78,30 @@ void _relayProviderStatus(unsigned char id, bool status) {
#endif #endif
#if RELAY_PROVIDER == RELAY_PROVIDER_LIGHT #if RELAY_PROVIDER == RELAY_PROVIDER_LIGHT
lightState(status);
// If the number of relays matches the number of light channels
// assume each relay controls one channel.
// If the number of relays is the number of channels plus 1
// assume the first one controls all the channels and
// the rest one channel each.
// Otherwise every relay controls all channels.
// TODO: this won't work with a mixed of dummy and real relays
// but this option is not allowed atm (YANGNI)
if (_relays.size() == lightChannels()) {
lightState(id, status);
lightState(true);
} else if (_relays.size() == lightChannels() + 1) {
if (id == 0) {
lightState(status);
} else {
lightState(id-1, status);
}
} else {
lightState(status);
}
lightUpdate(true, true); lightUpdate(true, true);
#endif #endif
#if RELAY_PROVIDER == RELAY_PROVIDER_RELAY #if RELAY_PROVIDER == RELAY_PROVIDER_RELAY
@ -146,6 +168,9 @@ bool relayStatus(unsigned char id, bool status, bool report, bool group_report)
rfbStatus(id, status); rfbStatus(id, status);
#endif #endif
// Update the pulse counter if the relay is already in the non-normal state (#454)
relayPulse(id);
} else { } else {
unsigned int current_time = millis(); unsigned int current_time = millis();


+ 16
- 9
code/espurna/rfbridge.ino View File

@ -48,7 +48,8 @@ typedef struct {
byte times; byte times;
} rfb_message_t; } rfb_message_t;
static std::queue<rfb_message_t> _rfb_message_queue; static std::queue<rfb_message_t> _rfb_message_queue;
Ticker _rfbTicker;
Ticker _rfb_ticker;
bool _rfb_ticker_active = false;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// PRIVATES // PRIVATES
@ -166,29 +167,35 @@ void _rfbSend() {
} }
// if there are still messages in the queue... // if there are still messages in the queue...
if (!_rfb_message_queue.empty()) {
_rfbTicker.once_ms(RF_SEND_DELAY, _rfbSend);
if (_rfb_message_queue.empty()) {
_rfb_ticker.detach();
_rfb_ticker_active = false;
} }
} }
void _rfbSend(byte * code, int times) {
void _rfbSend(byte * code, unsigned char times) {
char buffer[RF_MESSAGE_SIZE]; char buffer[RF_MESSAGE_SIZE];
_rfbToChar(code, buffer); _rfbToChar(code, buffer);
DEBUG_MSG_P(PSTR("[RFBRIDGE] Sending MESSAGE '%s' %d time(s)\n"), buffer, times);
DEBUG_MSG_P(PSTR("[RFBRIDGE] Enqueuing MESSAGE '%s' %d time(s)\n"), buffer, times);
rfb_message_t message; rfb_message_t message;
memcpy(message.code, code, RF_MESSAGE_SIZE); memcpy(message.code, code, RF_MESSAGE_SIZE);
message.times = times; message.times = times;
_rfb_message_queue.push(message); _rfb_message_queue.push(message);
_rfbSend();
// Enable the ticker if not running
if (!_rfb_ticker_active) {
_rfb_ticker_active = true;
_rfb_ticker.attach_ms(RF_SEND_DELAY, _rfbSend);
}
} }
#if RF_RAW_SUPPORT #if RF_RAW_SUPPORT
void _rfbSendRawOnce(byte *code, int length) {
void _rfbSendRawOnce(byte *code, unsigned char length) {
char buffer[length*2]; char buffer[length*2];
_rfbToChar(code, buffer, length); _rfbToChar(code, buffer, length);
DEBUG_MSG_P(PSTR("[RFBRIDGE] Sending RAW MESSAGE '%s'\n"), buffer); DEBUG_MSG_P(PSTR("[RFBRIDGE] Sending RAW MESSAGE '%s'\n"), buffer);
@ -304,10 +311,10 @@ void _rfbReceive() {
//DEBUG_MSG_P(PSTR("[RFBRIDGE] Received 0x%02X\n"), c); //DEBUG_MSG_P(PSTR("[RFBRIDGE] Received 0x%02X\n"), c);
if (receiving) { if (receiving) {
if (c == RF_CODE_STOP && (_uartpos == 1 || _uartpos == 10)) {
if (c == RF_CODE_STOP && (_uartpos == 1 || _uartpos == RF_MESSAGE_SIZE + 1)) {
_rfbDecode(); _rfbDecode();
receiving = false; receiving = false;
} else if (_uartpos < 10) {
} else if (_uartpos <= RF_MESSAGE_SIZE) {
_uartbuf[_uartpos++] = c; _uartbuf[_uartpos++] = c;
} else { } else {
// wrong message, should have received a RF_CODE_STOP // wrong message, should have received a RF_CODE_STOP


+ 13
- 6
code/espurna/scheduler.ino View File

@ -22,10 +22,11 @@ void _schWebSocketOnSend(JsonObject &root){
for (byte i = 0; i < SCHEDULER_MAX_SCHEDULES; i++) { for (byte i = 0; i < SCHEDULER_MAX_SCHEDULES; i++) {
if (!hasSetting("schSwitch", i)) break; if (!hasSetting("schSwitch", i)) break;
JsonObject &scheduler = sch.createNestedObject(); JsonObject &scheduler = sch.createNestedObject();
scheduler["schSwitch"] = getSetting("schSwitch", i, "");
scheduler["schAction"] = getSetting("schAction", i, "");
scheduler["schHour"] = getSetting("schHour", i, "");
scheduler["schMinute"] = getSetting("schMinute", i, "");
scheduler["schEnabled"] = getSetting("schEnabled", i, 1).toInt() == 1;
scheduler["schSwitch"] = getSetting("schSwitch", i, 0).toInt();
scheduler["schAction"] = getSetting("schAction", i, 0).toInt();
scheduler["schHour"] = getSetting("schHour", i, 0).toInt();
scheduler["schMinute"] = getSetting("schMinute", i, 0).toInt();
scheduler["schWDs"] = getSetting("schWDs", i, ""); scheduler["schWDs"] = getSetting("schWDs", i, "");
} }
} }
@ -45,6 +46,7 @@ void _schConfigure() {
if (delete_flag) { if (delete_flag) {
delSetting("schEnabled", i);
delSetting("schSwitch", i); delSetting("schSwitch", i);
delSetting("schAction", i); delSetting("schAction", i);
delSetting("schHour", i); delSetting("schHour", i);
@ -55,14 +57,16 @@ void _schConfigure() {
#if DEBUG_SUPPORT #if DEBUG_SUPPORT
int sch_enabled = getSetting("schEnabled", i, 1).toInt() == 1;
int sch_action = getSetting("schAction", i, 0).toInt(); int sch_action = getSetting("schAction", i, 0).toInt();
int sch_hour = getSetting("schHour", i, 0).toInt(); int sch_hour = getSetting("schHour", i, 0).toInt();
int sch_minute = getSetting("schMinute", i, 0).toInt(); int sch_minute = getSetting("schMinute", i, 0).toInt();
String sch_weekdays = getSetting("schWDs", i, ""); String sch_weekdays = getSetting("schWDs", i, "");
DEBUG_MSG_P( DEBUG_MSG_P(
PSTR("[SCH] Schedule #%d: %s switch #%d at %02d:%02d on %s\n"),
PSTR("[SCH] Schedule #%d: %s switch #%d at %02d:%02d on %s%s\n"),
i, sch_action == 0 ? "turn OFF" : sch_action == 1 ? "turn ON" : "toggle", sch_switch, i, sch_action == 0 ? "turn OFF" : sch_action == 1 ? "turn ON" : "toggle", sch_switch,
sch_hour, sch_minute, (char *) sch_weekdays.c_str()
sch_hour, sch_minute, (char *) sch_weekdays.c_str(),
sch_enabled ? "" : " (disabled)"
); );
#endif // DEBUG_SUPPORT #endif // DEBUG_SUPPORT
@ -104,6 +108,9 @@ void _schCheck() {
int sch_switch = getSetting("schSwitch", i, 0xFF).toInt(); int sch_switch = getSetting("schSwitch", i, 0xFF).toInt();
if (sch_switch == 0xFF) break; if (sch_switch == 0xFF) break;
// Skip disabled schedules
if (getSetting("schEnabled", i, 1).toInt() == 0) continue;
String sch_weekdays = getSetting("schWDs", i, ""); String sch_weekdays = getSetting("schWDs", i, "");
if (_schIsThisWeekday(sch_weekdays)) { if (_schIsThisWeekday(sch_weekdays)) {


+ 44
- 34
code/espurna/sensor.ino View File

@ -40,29 +40,11 @@ double _sensor_temperature_correction = SENSOR_TEMPERATURE_CORRECTION;
// Private // Private
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
String _magnitudeTopic(unsigned char type) {
char buffer[16] = {0};
if (type < MAGNITUDE_MAX) strncpy_P(buffer, magnitude_topics[type], sizeof(buffer));
return String(buffer);
}
unsigned char _magnitudeDecimals(unsigned char type) { unsigned char _magnitudeDecimals(unsigned char type) {
if (type < MAGNITUDE_MAX) return pgm_read_byte(magnitude_decimals + type); if (type < MAGNITUDE_MAX) return pgm_read_byte(magnitude_decimals + type);
return 0; return 0;
} }
String _magnitudeUnits(unsigned char type) {
char buffer[8] = {0};
if (type < MAGNITUDE_MAX) {
if ((type == MAGNITUDE_TEMPERATURE) && (_sensor_temperature_units == TMP_FAHRENHEIT)) {
strncpy_P(buffer, magnitude_fahrenheit, sizeof(buffer));
} else {
strncpy_P(buffer, magnitude_units[type], sizeof(buffer));
}
}
return String(buffer);
}
double _magnitudeProcess(unsigned char type, double value) { double _magnitudeProcess(unsigned char type, double value) {
if (type == MAGNITUDE_TEMPERATURE) { if (type == MAGNITUDE_TEMPERATURE) {
if (_sensor_temperature_units == TMP_FAHRENHEIT) value = value * 1.8 + 32; if (_sensor_temperature_units == TMP_FAHRENHEIT) value = value * 1.8 + 32;
@ -91,7 +73,7 @@ void _sensorWebSocketSendData(JsonObject& root) {
element["index"] = int(magnitude.global); element["index"] = int(magnitude.global);
element["type"] = int(magnitude.type); element["type"] = int(magnitude.type);
element["value"] = String(buffer); element["value"] = String(buffer);
element["units"] = _magnitudeUnits(magnitude.type);
element["units"] = magnitudeUnits(magnitude.type);
element["description"] = magnitude.sensor->slot(magnitude.local); element["description"] = magnitude.sensor->slot(magnitude.local);
element["error"] = magnitude.sensor->error(); element["error"] = magnitude.sensor->error();
@ -158,7 +140,7 @@ void _sensorAPISetup() {
sensor_magnitude_t magnitude = _magnitudes[magnitude_id]; sensor_magnitude_t magnitude = _magnitudes[magnitude_id];
String topic = _magnitudeTopic(magnitude.type);
String topic = magnitudeTopic(magnitude.type);
if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) topic = topic + "/" + String(magnitude.global); if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) topic = topic + "/" + String(magnitude.global);
apiRegister(topic.c_str(), [magnitude_id](char * buffer, size_t len) { apiRegister(topic.c_str(), [magnitude_id](char * buffer, size_t len) {
@ -181,9 +163,9 @@ void _sensorInitCommands() {
sensor_magnitude_t magnitude = _magnitudes[i]; sensor_magnitude_t magnitude = _magnitudes[i];
DEBUG_MSG_P(PSTR("[SENSOR] * %2d: %s @ %s (%s/%d)\n"), DEBUG_MSG_P(PSTR("[SENSOR] * %2d: %s @ %s (%s/%d)\n"),
i, i,
_magnitudeTopic(magnitude.type).c_str(),
magnitudeTopic(magnitude.type).c_str(),
magnitude.sensor->slot(magnitude.local).c_str(), magnitude.sensor->slot(magnitude.local).c_str(),
_magnitudeTopic(magnitude.type).c_str(),
magnitudeTopic(magnitude.type).c_str(),
magnitude.global magnitude.global
); );
} }
@ -546,7 +528,7 @@ void _magnitudesInit() {
new_magnitude.filter->resize(_sensor_report_every); new_magnitude.filter->resize(_sensor_report_every);
_magnitudes.push_back(new_magnitude); _magnitudes.push_back(new_magnitude);
DEBUG_MSG_P(PSTR("[SENSOR] -> %s:%d\n"), _magnitudeTopic(type).c_str(), _counts[type]);
DEBUG_MSG_P(PSTR("[SENSOR] -> %s:%d\n"), magnitudeTopic(type).c_str(), _counts[type]);
_counts[type] = _counts[type] + 1; _counts[type] = _counts[type] + 1;
@ -590,6 +572,38 @@ unsigned char magnitudeIndex(unsigned char index) {
return 0; return 0;
} }
String magnitudeTopic(unsigned char type) {
char buffer[16] = {0};
if (type < MAGNITUDE_MAX) strncpy_P(buffer, magnitude_topics[type], sizeof(buffer));
return String(buffer);
}
String magnitudeTopicIndex(unsigned char index) {
char topic[32] = {0};
if (index < _magnitudes.size()) {
sensor_magnitude_t magnitude = _magnitudes[index];
if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) {
snprintf(topic, sizeof(topic), "%s/%u", magnitudeTopic(magnitude.type).c_str(), magnitude.global);
} else {
snprintf(topic, sizeof(topic), "%s", magnitudeTopic(magnitude.type).c_str());
}
}
return String(topic);
}
String magnitudeUnits(unsigned char type) {
char buffer[8] = {0};
if (type < MAGNITUDE_MAX) {
if ((type == MAGNITUDE_TEMPERATURE) && (_sensor_temperature_units == TMP_FAHRENHEIT)) {
strncpy_P(buffer, magnitude_fahrenheit, sizeof(buffer));
} else {
strncpy_P(buffer, magnitude_units[type], sizeof(buffer));
}
}
return String(buffer);
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void sensorSetup() { void sensorSetup() {
@ -671,9 +685,9 @@ void sensorLoop() {
dtostrf(current, 1-sizeof(buffer), decimals, buffer); dtostrf(current, 1-sizeof(buffer), decimals, buffer);
DEBUG_MSG_P(PSTR("[SENSOR] %s - %s: %s%s\n"), DEBUG_MSG_P(PSTR("[SENSOR] %s - %s: %s%s\n"),
magnitude.sensor->slot(magnitude.local).c_str(), magnitude.sensor->slot(magnitude.local).c_str(),
_magnitudeTopic(magnitude.type).c_str(),
magnitudeTopic(magnitude.type).c_str(),
buffer, buffer,
_magnitudeUnits(magnitude.type).c_str()
magnitudeUnits(magnitude.type).c_str()
); );
} }
#endif // SENSOR_DEBUG #endif // SENSOR_DEBUG
@ -693,20 +707,16 @@ void sensorLoop() {
dtostrf(filtered, 1-sizeof(buffer), decimals, buffer); dtostrf(filtered, 1-sizeof(buffer), decimals, buffer);
#if BROKER_SUPPORT #if BROKER_SUPPORT
brokerPublish(_magnitudeTopic(magnitude.type).c_str(), magnitude.local, buffer);
brokerPublish(magnitudeTopic(magnitude.type).c_str(), magnitude.local, buffer);
#endif #endif
#if MQTT_SUPPORT #if MQTT_SUPPORT
if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) {
mqttSend(_magnitudeTopic(magnitude.type).c_str(), magnitude.global, buffer);
} else {
mqttSend(_magnitudeTopic(magnitude.type).c_str(), buffer);
}
mqttSend(magnitudeTopicIndex(i).c_str(), buffer);
#if SENSOR_PUBLISH_ADDRESSES #if SENSOR_PUBLISH_ADDRESSES
char topic[32]; char topic[32];
snprintf(topic, sizeof(topic), "%s/%s", SENSOR_ADDRESS_TOPIC, _magnitudeTopic(magnitude.type).c_str());
snprintf(topic, sizeof(topic), "%s/%s", SENSOR_ADDRESS_TOPIC, magnitudeTopic(magnitude.type).c_str());
if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) { if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) {
mqttSend(topic, magnitude.global, magnitude.sensor->address(magnitude.local).c_str()); mqttSend(topic, magnitude.global, magnitude.sensor->address(magnitude.local).c_str());
} else { } else {
@ -718,9 +728,9 @@ void sensorLoop() {
#if INFLUXDB_SUPPORT #if INFLUXDB_SUPPORT
if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) { if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) {
idbSend(_magnitudeTopic(magnitude.type).c_str(), magnitude.global, buffer);
idbSend(magnitudeTopic(magnitude.type).c_str(), magnitude.global, buffer);
} else { } else {
idbSend(_magnitudeTopic(magnitude.type).c_str(), buffer);
idbSend(magnitudeTopic(magnitude.type).c_str(), buffer);
} }
#endif // INFLUXDB_SUPPORT #endif // INFLUXDB_SUPPORT


+ 63
- 23
code/espurna/ssdp.ino View File

@ -10,34 +10,74 @@ https://github.com/esp8266/Arduino/issues/2283#issuecomment-299635604
#if SSDP_SUPPORT #if SSDP_SUPPORT
#include <libs/SSDPDevice.h>
#include <ESP8266SSDP.h>
const char _ssdp_template[] PROGMEM =
"<?xml version=\"1.0\"?>"
"<root xmlns=\"urn:schemas-upnp-org:device-1-0\">"
"<specVersion>"
"<major>1</major>"
"<minor>0</minor>"
"</specVersion>"
"<URLBase>http://%s:%u/</URLBase>"
"<device>"
"<deviceType>%s</deviceType>"
"<friendlyName>%s</friendlyName>"
"<presentationURL>/</presentationURL>"
"<serialNumber>%u</serialNumber>"
"<modelName>%s</modelName>"
"<modelNumber>%s</modelNumber>"
"<modelURL>%s</modelURL>"
"<manufacturer>%s</manufacturer>"
"<manufacturerURL>%s</manufacturerURL>"
"<UDN>uuid:38323636-4558-4dda-9188-cda0e6%06x</UDN>"
"</device>"
"</root>\r\n"
"\r\n";
void ssdpSetup() { void ssdpSetup() {
SSDPDevice.setName(getSetting("hostname"));
SSDPDevice.setDeviceType("urn:schemas-upnp-org:device:BinaryLight:1");
SSDPDevice.setSchemaURL("description.xml");
SSDPDevice.setSerialNumber(ESP.getChipId());
SSDPDevice.setURL("/");
SSDPDevice.setModelName(DEVICE);
SSDPDevice.setModelNumber("");
SSDPDevice.setManufacturer(MANUFACTURER);
#if WEB_SUPPORT
webServer()->on("/description.xml", HTTP_GET, [](AsyncWebServerRequest *request) {
DEBUG_MSG_P(PSTR("[SSDP] Schema request\n"));
String schema = SSDPDevice.schema();
request->send(200, "application/xml", schema.c_str());
});
#endif
// Register loop
espurnaRegisterLoop(ssdpLoop);
webServer()->on("/description.xml", HTTP_GET, [](AsyncWebServerRequest *request) {
}
DEBUG_MSG_P(PSTR("[SSDP] Schema request\n"));
IPAddress ip = WiFi.localIP();
uint32_t chipId = ESP.getChipId();
char response[strlen_P(_ssdp_template) + 100];
snprintf_P(response, sizeof(response), _ssdp_template,
WiFi.localIP().toString().c_str(), // ip
webPort(), // port
SSDP_DEVICE_TYPE, // device type
getSetting("hostname").c_str(), // friendlyName
chipId, // serialNumber
APP_NAME, // modelName
APP_VERSION, // modelNumber
APP_WEBSITE, // modelURL
DEVICE_NAME, // manufacturer
"", // manufacturerURL
chipId // UUID
);
request->send(200, "text/xml", response);
});
SSDP.setSchemaURL("description.xml");
SSDP.setHTTPPort(webPort());
SSDP.setDeviceType(SSDP_DEVICE_TYPE); //https://github.com/esp8266/Arduino/issues/2283
SSDP.setName(getSetting("hostname"));
SSDP.setSerialNumber(String(ESP.getChipId()));
SSDP.setModelName(APP_NAME);
SSDP.setModelNumber(APP_VERSION);
SSDP.setModelURL(APP_WEBSITE);
SSDP.setManufacturer(DEVICE_NAME);
SSDP.setManufacturerURL("");
SSDP.setURL("/");
SSDP.begin();
DEBUG_MSG_P(PSTR("[SSDP] Started\n"));
void ssdpLoop() {
SSDPDevice.handleClient();
} }
#endif // SSDP_SUPPORT #endif // SSDP_SUPPORT

+ 2604
- 2602
code/espurna/static/index.html.gz.h
File diff suppressed because it is too large
View File


+ 7
- 0
code/espurna/telnet.ino View File

@ -49,6 +49,13 @@ unsigned char _telnetWrite(void *data, size_t len) {
void _telnetData(unsigned char clientId, void *data, size_t len) { void _telnetData(unsigned char clientId, void *data, size_t len) {
// Skip first message since it's always garbage
static bool first = true;
if (first) {
first = false;
return;
}
// Capture close connection // Capture close connection
char * p = (char *) data; char * p = (char *) data;
if ((strncmp(p, "close", 5) == 0) || (strncmp(p, "quit", 4) == 0)) { if ((strncmp(p, "close", 5) == 0) || (strncmp(p, "quit", 4) == 0)) {


+ 13
- 9
code/espurna/web.ino View File

@ -277,6 +277,14 @@ AsyncWebServer * webServer() {
return _server; return _server;
} }
unsigned int webPort() {
#if ASYNC_TCP_SSL_ENABLED & WEB_SSL_ENABLED
return 443;
#else
return getSetting("webPort", WEB_PORT).toInt();
#endif
}
void webLog(AsyncWebServerRequest *request) { void webLog(AsyncWebServerRequest *request) {
DEBUG_MSG_P(PSTR("[WEBSERVER] Request: %s %s\n"), request->methodToString(), request->url().c_str()); DEBUG_MSG_P(PSTR("[WEBSERVER] Request: %s %s\n"), request->methodToString(), request->url().c_str());
} }
@ -287,11 +295,7 @@ void webSetup() {
snprintf_P(_last_modified, sizeof(_last_modified), PSTR("%s %s GMT"), __DATE__, __TIME__); snprintf_P(_last_modified, sizeof(_last_modified), PSTR("%s %s GMT"), __DATE__, __TIME__);
// Create server // Create server
#if ASYNC_TCP_SSL_ENABLED & WEB_SSL_ENABLED
unsigned int port = 443;
#else
unsigned int port = getSetting("webPort", WEB_PORT).toInt();
#endif
unsigned int port = webPort();
_server = new AsyncWebServer(port); _server = new AsyncWebServer(port);
// Rewrites // Rewrites
@ -323,12 +327,12 @@ void webSetup() {
// Run server // Run server
#if ASYNC_TCP_SSL_ENABLED & WEB_SSL_ENABLED #if ASYNC_TCP_SSL_ENABLED & WEB_SSL_ENABLED
_server->onSslFileRequest(_onCertificate, NULL);
_server->beginSecure("server.cer", "server.key", NULL);
_server->onSslFileRequest(_onCertificate, NULL);
_server->beginSecure("server.cer", "server.key", NULL);
#else #else
_server->begin();
_server->begin();
#endif #endif
DEBUG_MSG_P(PSTR("[WEBSERVER] Webserver running on port %d\n"), port);
DEBUG_MSG_P(PSTR("[WEBSERVER] Webserver running on port %u\n"), port);
} }


+ 3
- 4
code/html/custom.js View File

@ -151,7 +151,7 @@ function validateForm(form) {
// These fields will always be a list of values // These fields will always be a list of values
var is_group = [ var is_group = [
"ssid", "pass", "gw", "mask", "ip", "dns", "ssid", "pass", "gw", "mask", "ip", "dns",
"schSwitch","schAction","schHour","schMinute","schWDs",
"schEnabled", "schSwitch","schAction","schHour","schMinute","schWDs",
"relayBoot", "relayPulse", "relayTime", "relayBoot", "relayPulse", "relayTime",
"mqttGroup", "mqttGroupInv", "mqttGroup", "mqttGroupInv",
"dczRelayIdx", "dczMagnitude", "dczRelayIdx", "dczMagnitude",
@ -1001,6 +1001,7 @@ function processData(data) {
Object.keys(schedule).forEach(function(key) { Object.keys(schedule).forEach(function(key) {
$("input[name='" + key + "']", line).val(schedule[key]); $("input[name='" + key + "']", line).val(schedule[key]);
$("select[name='" + key + "']", line).prop("value", schedule[key]); $("select[name='" + key + "']", line).prop("value", schedule[key]);
$(":checkbox", line).prop("checked", schedule[key]);
}); });
} }
return; return;
@ -1246,9 +1247,7 @@ $(function() {
$(".button-add-network").on("click", function() { $(".button-add-network").on("click", function() {
$(".more", addNetwork()).toggle(); $(".more", addNetwork()).toggle();
}); });
$(".button-add-schedule").on("click", function() {
$("div.more", addSchedule()).toggle();
});
$(".button-add-schedule").on("click", addSchedule);
$(document).on("change", "input", hasChanged); $(document).on("change", "input", hasChanged);
$(document).on("change", "select", hasChanged); $(document).on("change", "select", hasChanged);


+ 7
- 4
code/html/index.html View File

@ -146,7 +146,7 @@
&copy; 2016-2018<br /> &copy; 2016-2018<br />
Xose Pérez<br/> Xose Pérez<br/>
<a href="http://tinkerman.cat" target="_blank">http://tinkerman.cat</a><br/> <a href="http://tinkerman.cat" target="_blank">http://tinkerman.cat</a><br/>
<a href="https://bitbucket.org/xoseperez/espurna" target="_blank">ESPurna @ Bitbucket</a><br/>
<a href="https://github.com/xoseperez/espurna" target="_blank">ESPurna @ GitHub</a><br/>
GPLv3 license<br/> GPLv3 license<br/>
</div> </div>
@ -1083,11 +1083,11 @@
<label class="pure-u-1 pure-u-lg-1-4">When time is</label> <label class="pure-u-1 pure-u-lg-1-4">When time is</label>
<div class="pure-u-1-4 pure-u-lg-1-5"> <div class="pure-u-1-4 pure-u-lg-1-5">
<input class="pure-u-2-3" name="schHour" type="number" min="0" step="1" max="23" /> <input class="pure-u-2-3" name="schHour" type="number" min="0" step="1" max="23" />
<div class="pure-u-1-4 hint center"> h</div>
<div class="pure-u-1-4 hint center">&nbsp;h</div>
</div> </div>
<div class="pure-u-1-4 pure-u-lg-1-5"> <div class="pure-u-1-4 pure-u-lg-1-5">
<input class="pure-u-2-3" name="schMinute" type="number" min="0" step="1" max="59" /> <input class="pure-u-2-3" name="schMinute" type="number" min="0" step="1" max="59" />
<div class="pure-u-1-4 hint center"> m</div>
<div class="pure-u-1-4 hint center">&nbsp;m</div>
</div> </div>
<div class="pure-u-0 pure-u-lg-1-3"></div> <div class="pure-u-0 pure-u-lg-1-3"></div>
@ -1095,7 +1095,7 @@
<div class="pure-u-2-5 pure-u-lg-1-5"> <div class="pure-u-2-5 pure-u-lg-1-5">
<input class="pure-u-23-24 pure-u-lg-23-24" name="schWDs" type="text" maxlength="15" tabindex="0" value="1,2,3,4,5,6,7" /> <input class="pure-u-23-24 pure-u-lg-23-24" name="schWDs" type="text" maxlength="15" tabindex="0" value="1,2,3,4,5,6,7" />
</div> </div>
<div class="pure-u-3-5 pure-u-lg-1-2 hint center">1 for Monday, 2 for Tuesday...</div>
<div class="pure-u-3-5 pure-u-lg-1-2 hint center">&nbsp;1 for Monday, 2 for Tuesday...</div>
<label class="pure-u-1 pure-u-lg-1-4">Action</label> <label class="pure-u-1 pure-u-lg-1-4">Action</label>
<div class="pure-u-1 pure-u-lg-1-5"> <div class="pure-u-1 pure-u-lg-1-5">
@ -1108,6 +1108,9 @@
<select class="pure-u-1 pure-u-lg-1-5 isrelay" name="schSwitch"></select> <select class="pure-u-1 pure-u-lg-1-5 isrelay" name="schSwitch"></select>
<div class="pure-u-0 pure-u-lg-1-5"></div> <div class="pure-u-0 pure-u-lg-1-5"></div>
<label class="pure-u-1 pure-u-lg-1-4">Enabled</label>
<div class="pure-u-1 pure-u-lg-3-4"><input type="checkbox" name="schEnabled" /></div>
<div class="pure-u-0 pure-u-lg-1-4"></div> <div class="pure-u-0 pure-u-lg-1-4"></div>
<button class="pure-button button-del-schedule" type="button">Delete schedule</button> <button class="pure-button button-del-schedule" type="button">Delete schedule</button>


+ 24
- 0
code/platformio.ini View File

@ -881,6 +881,30 @@ upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200 monitor_baud = 115200
extra_scripts = ${common.extra_scripts} extra_scripts = ${common.extra_scripts}
[env:magichome-led-controller-23]
platform = ${common.platform}
framework = arduino
board = esp01_1m
board_flash_mode = dout
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DMAGICHOME_LED_CONTROLLER_23
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:magichome-led-controller-23-ota]
platform = ${common.platform}
framework = arduino
board = esp01_1m
board_flash_mode = dout
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DMAGICHOME_LED_CONTROLLER_23
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:huacanxing-h801] [env:huacanxing-h801]
platform = ${common.platform} platform = ${common.platform}
framework = arduino framework = arduino


Loading…
Cancel
Save