Compare commits

..
77 Commits
Author SHA1 Message Date
ESPEasy release bot d2e2522c07 automaticly updated release notes for mega-20180104 2018-01-04 03:13:01 +00:00
ESPEasy release bot 4a212302e0 changed date format of nightly builds 2018-01-03 14:51:40 +00:00
ESPEasy release bot 993dd7ade3 automaticly updated release notes for mega-01032018 2018-01-03 04:00:06 +00:00
Edwin Eefting d544fc84e8 changed readme to reflect mega branch and automated builds 2018-01-03 01:04:18 +01:00
Edwin Eefting e6dba4456c Merge branch 'v2.0' into mega 2018-01-03 00:52:03 +01:00
Edwin Eefting d2777a9b15 updated travis link to reflect v2.0 2018-01-03 00:50:49 +01:00
Edwin Eefting c7d12bb798 Merge branch 'v2.0' into mega 2018-01-03 00:48:13 +01:00
ESPEasy release bot ef912a4484 automaticly updated release notes for mega-01022018 2018-01-02 23:32:50 +00:00
ESPEasy release bot b4debd9559 created releasebot script 2018-01-02 23:30:53 +00:00
Edwin Eefting d7277649dd merged v2.0 branch. disabled memory checker (takes too long, perhaps enable it via a commit keyword?) 2018-01-03 00:28:22 +01:00
Edwin Eefting 33ec7e5240 Merge branch 'v2.0' into mega 2018-01-02 12:49:55 +01:00
Gijs NoorlanderandDatuX d62b692b3b [SDS011] Allow the sensor to sleep to extend sensor lifetime (#668)
* [SDS011] Add send commands to sensor

In the library used to communicate to the SDS011 sensor was only support to receive data from the sensor and not query the sensor or set another mode.
This is needed for #499 , to let the sensor sleep.

N.B. code is not yet tested, only implemented while reading the datasheet "Laser Dust Sensor Control Protocol V1.3"

* [SDS011] Lessen load on ESP by polling less frequent and use SoftSerial

The default setting were to set the delay to 0 and use an own software serial implementation.
This caused frequent timeouts on the web interface, WiFi reconnects, etc.
Now the already present SoftSerial is being used. This will gather all the data from the serial port and thus there is no need to poll 50 times a second.
Now the ESP is much more responsive.

* [SDS011] Allow the sensor to sleep to extend sensor lifetime

The internal laser of the SDS011 only will last for about 1 year when ran continuously.
When the RX of the sensor is connected, it can be set to sleep for N minutes between measurements. This will extend the lifetime of the sensor and reduce power consumption.
This sleep time is stored inside the flash of the sensor, so it can be set once and then the RX on the sensor could be disconnected again to be used for other purposes.
2018-01-02 12:22:57 +01:00
paulv888andDatuX 493bfd56b9 usesID = true (#666)
fixes #646
2018-01-02 11:41:01 +01:00
krikkandDatuX abbfa24ca6 added support for the TSL2591 Sensor based on Adafruit Library (#661)
* initial support for TSL2591 sensor

* return lux, visible, ir and full light separately

* better plugin init

* check sensor initialization before reading it..

* incorporated a few pending fixes for the adafruit library

* minor typo
2017-12-31 15:35:44 +01:00
Gijs NoorlanderandDatuX fae1edc859 [Security] Add IP-based filtering to web interface and http-commands. (#653)
* [mega] Detect client IP for SysInfo page and some cleanup

Added formatIP functions for readability and add client IP to SystemInfo page as preparation to detect origin just to get an idea of possibilities for #647.
Also added some reserve() statements to Strings to prevent heap fragmentation.

* [mega] Cleanup formatIP calls

* [security] #647 Add IP filtering to web interface and commands

As discussed in #647:
In the Config tab, a "Client IP filtering" section is added.
This allows for 3 levels of IP filtering:
* "Allow All" - does not imply any filtering based on IP address of the client.
* "Allow Local Subnet" - Allow only clients from within the local subnet, based on IP and subnetmask of the ESP.
* "Allow IP range" - Allow only clients within a range of IP-addresses.

Settings like these are very likely to lock out the rightful owner, so there are also two commands added, which can be sent via the serial connection.
* accessinfo
* clearaccessblock

The first one just displays the current active IP filtering.
The "clearaccessblock" command will temporarily disable the access filtering. This allows the user to login and reset the access filtering.

"Allow Local Subnet" is set as factory default.
Only when first loading a new firmware with this feature and existing configuration, the "All Allowed" is active (the old default)
2017-12-31 15:31:20 +01:00
s0170071andDatuX a9a741f775 fix chunking (#649)
* change chunking 

so that manual chunking is only done with core 2.3.0. 2.4.0rc2 and later do chunking web transfer implicitly

* Update WebServer.ino
2017-12-28 20:16:03 +01:00
Edwin Eefting c0d482e4fc merged v2.0 fixes 2017-12-28 19:01:16 +01:00
Bartłomiej ZimońandDatuX b5cabdc775 Update _C002.ino (#645)
related to #636
2017-12-18 23:14:11 +01:00
Gijs NoorlanderandDatuX c71a43c3a6 Reduce iRAM usage for plugins using SoftwareSerial (#631)
* [addLib] Added SoftwareSerial library

Added latest version from: https://github.com/plerup/espsoftwareserial

* [renLib] Renamed files to avoid conflicts with existing code

* [renLib] Changed include according to rename

* [renLib] Renamed all occurences and includes and removed unused pins

Renamed to make sure all plugins use the 'new' ESPeasySoftwareSerial.
Also added pinToIndex function to reduce memory footprint with about 150 Bytes, as described in issue #630

* [unused pins] Adjust indices in object list

Forgot to change the indices in the object list of SoftwareSerial

* Simple patch for timeouts

As mentioned in this issue: https://github.com/plerup/espsoftwareserial/issues/54

* [SoftSerial] Set ObjList static

Set the object list static to share all SoftwareSerial iRAM used as described in #630

* [revertLib] Revert to old version lib, since new version uses more iram

Just to test with old version, originally available in 2.3.0 library, to see if memory usage improves.

* [test] Reduce number of ports to 1 and lower buffer size to 18 for MHZ19

Just as a test, to see what happens to the iRAM usage, lower the number of concurrent softserial ports to 1.
Also the default buffer size = 64 Bytes. The MH-Z19 sensor can do with less, since a response will be up to 9 bytes, a 18-byte buffer allows for 2 messages to be stored.

* Enable usage of up to 10 concurrent softserial and reduce variable sizes

Re-enable use of up to 10 concurrent software serials.
Also reduce the variable sizes to smaller ranges. (e.g. uint8 instead of int)

* [test] Limit number of concurrent software serial devices

Earlier tests show the amount of iRAM used is somewhat related to the maximum number of allowed software serial ports.
In this test it is set to 3 and they are assigned through first come first served a slot.
2017-12-18 22:02:53 +01:00
Edwin Eefting cd01283ac6 Merge branch 'v2.0' into mega 2017-12-18 21:26:06 +01:00
M0ebiu5andDatuX 7ce1077bd6 P022_PCA9685 added change frequency - P038_NeoPixel added RGBW strips (SK6812) (#638)
* added change frequency

* rgbw test

* PCA9685 change frequency

* Cleanup RGBW implementation

* Added instructions
2017-12-18 21:18:39 +01:00
DaMandDatuX f9701d1c7b [Domoticz HTTP] Compatibility fix for BMP280 (#636) 2017-12-18 21:13:34 +01:00
GrovkillenandDatuX e764830113 Updated "/pinstates" page: Made the plugin number column display "P001" instead of "1" and "P012" instead of "12". 2017-12-18 21:11:00 +01:00
GHolliandDatuX 9646457b50 Cosmetics: fixing typos. (#628)
* Optimisation: save RAM.

* Another RAM optimisation (freeing RAM by moving static data from RAM to program memory).

* Fixing user-visible typos.

* Fixing typos in variables and comments.

* Fixing typos in comments.

* Revert changes of other pull request.
2017-12-08 14:18:24 +01:00
GrovkillenandDatuX 7346e55e0d Updated ESPTOOLS.exe from 0.4.6 to 0.4.12 (#627)
* Add files via upload

* Add files via upload

* Updated ESPTOOLS.exe from 0.4.6 to 0.4.12

See releases here: https://github.com/igrr/esptool-ck/releases
2017-12-08 13:57:04 +01:00
fensoftandDatuX ae38a8cb4f added #define FEATURE_SD (permit a flash size reduction of ~10k) (#568) 2017-12-08 13:56:13 +01:00
Sen HaerensandDatuX df46a4a5fc Enhanced system info layout (#624)
* Enhance sysinfo page layout

* Added hex notation for chip IDs

* Fixed comment
2017-12-08 13:48:17 +01:00
GrovkillenandDatuX 7c6797a141 Move "TTP229 keypad" and "Encoder" plugin from "testing" to "normal" (#619)
* Add files via upload

* Add files via upload
2017-12-04 21:58:25 +01:00
mvdbro 83abac8c5e Fix #599 2017-12-03 15:13:29 +01:00
s0170071andDatuX 5ba6b2f335 split IP addrress (#605)
The system variable %ip% truncates the last octet or so when printed on small displays. Now there are four new variables %ip1%, %ip2%... so that the octet printout can be distibuted across two lines.
2017-11-23 19:04:59 +01:00
Edwin Eefting 0d4ba7c6f1 testing for ds18b20 2017-11-22 03:35:29 +01:00
Edwin Eefting a1fc351183 fix #588. parseTemplate() now only checks enabled taskes for [] macros 2017-11-22 03:33:34 +01:00
GrovkillenandDatuX 33a6c39fc4 Changed bin file names to be more descriptive. (#597)
* Changed bin file names to be more descriptive.

* Fixed TRAVIS check
2017-11-21 23:40:19 +01:00
papperoneandDatuX f853f6ef25 deleted GPIO notes referring to 75HC595 not supported (#591) 2017-11-20 22:52:01 +01:00
Edwin Eefting 7a2d114360 fix illegal string manipulations in PLUGIN_WRITE for some plugins. fixes #347 and #460 2017-11-16 03:01:14 +01:00
Edwin Eefting 0157f387ee Merge branch 'v2.0' into mega 2017-11-16 02:02:22 +01:00
sakinitandDatuX c23be231e1 Fix p1 wifi gateway module (#587)
* Fix receiving illegal characters using Domoticz

* Update P1GatewayServer life-cycle
2017-11-16 00:24:34 +01:00
Gijs NoorlanderandDatuX 00f5c36919 [P039 Thermocouple] Handling negative values and proper error logging (#586)
Cppcheck warned for 'suspicious code':
[src\_P039_Thermocouple.ino:254]: (warning) Suspicious code: sign conversion of -1 in calculation because '-1' has a negative value

I agree with cppcheck that the code is at least suspicious and probably compiler dependent.
So in order to let cppcheck no longer output a warning and make it a bit more readable, I made this change.

Also added logs to indicate errors reported by the sensor.
2017-11-16 00:05:23 +01:00
Edwin Eefting c960175ec1 set lcd to NULL by default. #584 2017-11-15 23:57:01 +01:00
Gijs NoorlanderandDatuX e456604436 [LCD plugin] Added check of LCD object before dereferencing it (#584)
Possible fix for #581.
Just looking at the description of the problem, this may be causing the crashes,since the commands may be trying to dereference the LCD pointer while it still is NULL.
2017-11-15 23:55:29 +01:00
GrovkillenandDatuX ac4657e77f Added categories... (#552) 2017-11-14 21:28:53 +01:00
papperoneandDatuX 3817427e79 Update _P073_7DGT.ino (#553) 2017-11-13 00:49:28 +01:00
Edwin Eefting 0200b3c63e fix travis build errors. disable cpp checking for now 2017-11-13 00:26:21 +01:00
Edwin Eefting 972a1a5703 Merge branch 'mega' of github.com:letscontrolit/ESPEasy into mega 2017-11-12 23:10:27 +01:00
mvdbro 73c22176b8 ESP32 fixed chunked HTTP transfer 2017-11-05 09:19:26 +01:00
mvdbro 4db036f350 ESP32 fix UDP instability 2017-11-04 17:15:24 +01:00
mvdbro 52223f0a20 ESP32 Enabled OTA 2017-11-04 10:38:14 +01:00
mvdbro 907ad0faf6 ESP32 fix FreeRAM reporting 2017-10-29 14:34:46 +01:00
mvdbro 887e10c947 ESP32 Rules/ADC/PWM 2017-10-28 16:07:00 +02:00
mvdbro b4c463e452 ESP32 IRAM/Deepsleep 2017-10-27 17:04:45 +02:00
mvdbro 66ba9b1f46 First preparations for ESP32 2017-10-25 16:10:16 +02:00
Edwin Eefting 7db50811ba esptest stuff 2017-10-23 20:44:23 +02:00
Edwin Eefting 17d20705ff smooth out testing code 2017-10-23 00:44:00 +02:00
Edwin Eefting e3bd782a42 test fixes 2017-10-22 23:20:07 +02:00
Edwin Eefting b073379fff fixed bug in oled upstream lib 2017-10-16 17:29:26 +02:00
Edwin Eefting b89d8ff946 fix warnings 2017-10-16 17:19:48 +02:00
Gijs NoorlanderandDatuX 22ad971c8e Support both SSD1306 and SH1106 OLED in OLED_Framed plugin (#509)
* [SSD1306] Upgrade library to version 3.0

The library at https://github.com/squix78/esp8266-oled-ssd1306 has to be initialized differently in version 3.0

Known issue: The font for 3 lines is not working, so temporary used the same font as for 4 ilnes. The online font generator is currently unavailable at http://oleddisplay.squix.ch/

* OLED framed improve header footer

The header now has better visible WiFi bars indicator and alternates the device name and the connected WiFi SSID.

The bottom part now only shows dots for the pages with visible data instead of the maximum number of pages possible.

* [SSD1306] Upgrade library to version 3.2.7

Forgot to commit deletion of obsolete files in previous commit.

* [SSD1306] Added 12pt font for version 3.x of the library

The font generator is online again: http://oleddisplay.squix.ch/#/home 
Added Dialog Plain 12 font for the 3-line display mode.

* [OLED_Framed] Allow to use either SSD1306 or SH1106

The new OLED library  allows to use SH1106 and SSD1306 controler.
Added support for both with an selector to select the available controler.

* [OLED_Framed] Only destruct and construct display object when changed

* [OLED Framed] Add contrast setting to display

Both SSD1306 and SH1106 support setting the contrast.

* Update _P036_FrameOLED.ino
2017-10-16 16:55:22 +02:00
Edwin Eefting ab06cc3703 merged v2.0 fix for MHZ19 (was already fixed in a different way) 2017-10-16 01:54:37 +02:00
Edwin Eefting 8a5cc5f2bd fix plugin id (starting with a 0 makes it octal in c++ :( ) 2017-10-16 01:47:57 +02:00
papperoneandDatuX 6919baf23c Plugin 073 - 7-segment display plugin TM1637/MAX7219 2017-10-16 01:44:56 +02:00
Gijs NoorlanderandDatuX ddedb215c4 [MH-Z19] Allow for B-version and add filtering (#525)
* [MH-Z19] Allow for B-version and add filtering

The "B" version of the sensor does not output an S value, but does internally apply a dynamic response filter on the samples based on the amount of fluctiation in the data.
The implemented filter does something similar for the "A" version and for both adds the option for an extra delay filter to smooth the data.

Default filter setting ("off") is the old behavior, where only stable values are allowed.

* [MH-Z19] Improve label texts and logging

The first commit for the filtering had some confusing text labels.
Also it would be nice to see the effect of filtering in the logs.
2017-10-16 01:36:43 +02:00
Tomasz TorczandDatuX 08d4d817f6 retain MQTT LWT messages (#516)
Retaining will messages allows monitoring agent to receive full info about clients state.
Without retaining, the monitoring agent will only be informed about events (connect/connection lost) happening during agent's connection to broker. Any reconnect would cause monitoring agent to lose state.
2017-10-16 01:18:45 +02:00
Edwin Eefting e8bdcfbaf2 keep TASKS_PER_PAGE at default value of 4 2017-10-16 01:16:55 +02:00
Edwin Eefting 743fb4494e improvement: Configurable number of tasks for "Devices" page #510
(by hexenmeister)
2017-10-16 01:15:34 +02:00
MichaelandDatuX 0a4bc7fad6 src/Hardware.ino: make it possible to use GPIO-0 (D3) as Pin_sd_cs (#508) 2017-10-16 01:04:12 +02:00
MichaelandDatuX 49d0b16324 WebServer.ino: enhance handle_SDfilelist() (#507) 2017-10-16 01:03:42 +02:00
Gijs NoorlanderandDatuX de479d6188 [SSD1306] Feature/oled 1306 library upgrade (#501)
* [SSD1306] Upgrade library to version 3.0

The library at https://github.com/squix78/esp8266-oled-ssd1306 has to be initialized differently in version 3.0

Known issue: The font for 3 lines is not working, so temporary used the same font as for 4 ilnes. The online font generator is currently unavailable at http://oleddisplay.squix.ch/

* OLED framed improve header footer

The header now has better visible WiFi bars indicator and alternates the device name and the connected WiFi SSID.

The bottom part now only shows dots for the pages with visible data instead of the maximum number of pages possible.

* [SSD1306] Upgrade library to version 3.2.7

Forgot to commit deletion of obsolete files in previous commit.

* [SSD1306] Added 12pt font for version 3.x of the library

The font generator is online again: http://oleddisplay.squix.ch/#/home 
Added Dialog Plain 12 font for the 3-line display mode.
2017-10-16 01:00:30 +02:00
Gijs NoorlanderandDatuX 3fd3e13dc7 OLED framed improve header footer (#495)
The header now has better visible WiFi bars indicator and alternates the device name and the connected WiFi SSID.

The bottom part now only shows dots for the pages with visible data instead of the maximum number of pages possible.
2017-10-16 00:55:25 +02:00
BadWolf42andDatuX d7d913d439 Dallas Plugin enhanced : no more "delay()" (#488)
* Enhanced Dallas pooling to avoid use of delay(800)

DS_readTemp has been split in 2: DS_convertTemp and DS_readonlyTemp.
DS_convertTemp is first called after DS_setResolution.
Then DS_convertTemp is called after temp has been read.
DS_readTemp has been kept for compatibility.
The only downside is that you read the temperature of previous query (value set by Timer/TDT option).

* typo

* Moved to Environment + code cleaning

- Moved Plugin from Temperature to Environment
- Modified Plugin_004_DS_crc8 to check CRC8, not return it
- Renamed Plugin_004_DS_convertTemp to Plugin_004_DS_startConvertion and removed useless vars in it
- Removed unneed braces and empty lines
- Added comments
2017-10-16 00:51:05 +02:00
SightofSilenceandDatuX 5c4ae3820b Add System Variable for day, month and year / Fix for "Calculate" function to recognize minus-sign (#485)
* Add files via upload

* Update Misc.ino

* Add files via upload
2017-10-16 00:47:58 +02:00
Gijs NoorlanderandDatuX 38774a20c6 Single function for format to user defined number decimals (#482)
* Single function for format to user defined number decimals

In a number of files the same long definition was cut and paste a lot to format  values to a user defined number of decimals.

Now a new simple function is added to Misc to perform this formatting, which results in more clean code, less prone to errors and a reduction in use of resources.

* Single function for format to user defined number decimals

In a number of files the same long definition was cut and paste a lot to format  values to a user defined number of decimals.

Now a new simple function is added to Misc to perform this formatting, which results in more clean code, less prone to errors and a reduction in use of resources.
2017-10-16 00:42:14 +02:00
Gijs NoorlanderandDatuX 9fc58bb4df P028 to support both BME280 and BMP280 to reduce resource usage (#481)
* P028 now supports both BME280 and BMP280

Both plugins P028 and P030 had a lot of code duplication. This takes up resources and is hard to maintain.
Now the P028 plugin can detect and use both sensors so P030 may be removed.

Only caveat is that the BMP280 does not measure humidity and thus actually is a 2-value sensor. The Domotics MQTT controller did not distinguish between them, but other controllers may do so.
When needed, the P030 plugin can still be a mere stub for the output and plugin definition and still share all code with P028.

* [BME280] Add temperature offset and improve read stability

The BME280/BMP280 may heat up internally if read too often and too long.
Also when built in a small container along with other sensors and the ESP, the sensor may read values which are too high.
To compensate for these higher readings, a constant offset may be applied in the device parameters.
This value is a signed integer value representing the offset in 1/10th degree Celsius.

Since the humidity is a relative value, depending on the temperature, this should be adjusted also.

Only this computed dew point temperature is also too high, due to the fact the sensor is warmer than the air and thus the perceived humidity is off.
To correct for this, half the offset temperature is being used to compute the dew point temperature.

The other improvement is the routine to read the sensor.

Using this routine, the sensor is only active for about 1.6 seconds each minute.
This prevents the sensor to heat up from its own readings and also allows stable readings using some filtering. (slamming a door does not affect the readings)

* [BMx280] Auto detect connected chip ID and show in Device config tab

Detect connected chip (BME280/BMP280) automatically and show detected device immediately in the Device config page next to the I2C address selection.

* [BME/BMP280] Perform reset at init

Just to make the reading a bit more stable when the sensor stops responding.
This is also done in the "official" Bosch github: https://github.com/BoschSensortec/BME280_driver

* [BMx280] Allow for more than one sensor 

As suggested in #491 for another sensor, its I2Caddress was handled incorrectly. The same applied to this plugin.
2017-10-16 00:27:04 +02:00
SloMustiandDatuX ca936ca42f implemewnted web activity timer tracker (#462) 2017-10-16 00:23:05 +02:00
Edwin Eefting 840fb6b647 Merge branch 'v2.0' into mega 2017-10-16 00:16:25 +02:00
denisfrenchandDatuX c80b5d6d78 Set MQTT clientid to %sysname% +/- Settings.Unit (#431) (#436) 2017-10-16 00:12:09 +02:00
hatzlhofferandDatuX 40067c514f added new display size 128x32 (#545)
added font size optimization
2017-10-16 00:06:59 +02:00
Alexander Schulz 139ae36d3e improvement: Configurable number of tasks for "Devices" page (TASKS_P…
…ER_PAGE)
2017-09-16 23:24:15 +02:00
151 changed files with 8552 additions and 11244 deletions
+4 -5
View File
@@ -1,10 +1,9 @@
# cmd: "cd {PROJECT_PATH}; platformio"
cmd: "platformio"
name: "Build with error highlighting (dev_ESP8266_4096)"
name: "Build with error highlighting (dev_4096)"
args:
- run --environment dev_ESP8266_4096
sh: true
cwd: "{PROJECT_PATH}"
- run --environment dev_4096
sh: true,
cwd: .
# env:
# VARIABLE1: "VALUE1"
# VARIABLE2: "VALUE2"
+3 -1
View File
@@ -26,6 +26,8 @@ Also there are more people on the forum that can help you with support.
* Incomplete or unstable plugins should have a PLUGIN_BUILD_DEV #ifdef around them. Also add [DEVELOPMENT] to the name.
* New plugins that seem to be working correctly should have a PLUGIN_BUILD_TESTING around until they are tested enough.
* Do not modify any of the variables passed to your PLUGIN_WRITE handler.
* New plugins that seem to be working correctly should have a PLUGIN_BUILD_TESTING around until they are tested enough. Also add [TESTING] to the name
* Also see our general guidelines at: https://www.letscontrolit.com/wiki/index.php/ESPEasyDevelopmentGuidelines
-1
View File
@@ -4,4 +4,3 @@
.piolibdeps
lib/readme.txt
src/Custom.h
+2 -7
View File
@@ -25,14 +25,9 @@ install:
- pip install -U platformio
script:
- cppcheck --enable=warning src/*.ino -q --force -I src --include=src/ESPEasy.ino --error-exitcode=1
# - cppcheck --enable=warning src/*.ino -q --force -I src --include=src/ESPEasy.ino --error-exitcode=1
# - ./memanalyzer.py ~/.platformio/packages/toolchain-xtensa/bin/xtensa-lx106-elf-objdump
- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run
# patch platformio core libs for PUYA bug (https://github.com/letscontrolit/ESPEasy/issues/650)
- cd patches; ./check_puya_patch; cd ..
- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -s --environment dev_ESP8266PUYA_1024
- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -s
before_deploy:
- ./before_deploy
+16 -27
View File
@@ -1,44 +1,33 @@
# ESPEasy (v2.0 stable branch)
# ESPEasy (mega branch)
Build status: [![Build Status](https://travis-ci.org/letscontrolit/ESPEasy.svg?branch=v2.0)](https://travis-ci.org/letscontrolit/ESPEasy)
Build status: [![Build Status](https://travis-ci.org/letscontrolit/ESPEasy.svg?branch=mega)](https://travis-ci.org/letscontrolit/ESPEasy)
Introduction and wiki: https://www.letscontrolit.com/wiki/index.php/ESPEasy#Introduction
**v2.0**
:warning:This is the stable branch for the next upcoming ESPeasy release (2.0.0).:warning:
If you're living on the edge and want the latest features and bugs, go to the development branch: https://github.com/letscontrolit/ESPEasy/tree/mega
If you're a developer: Bug fixes go into this v2.0 branch, we will merge them back to the development branch.
This is the development branch of ESPEasy. All new untested features go into this branch. Fixes from stable branches will also be merged in this one.
Check here to learn how to use this branch and help us improving ESPEasy: http://www.letscontrolit.com/wiki/index.php/ESPEasy#Source_code_development
## Versions
* v2.0-YYYYMMDD: These are the nightly builds. Once a day this is automaticly released whenever there are new changes. (this replaces the manual v2.0-devX release system)
* v2.0.0-betaX: as soon as we THINK everything is fixed, we start beta testing.
* v2.0.0-rcX: release candidates (almost stable)
* v2.0.0: This will be the first stable release. After this we will use more standard numbering. Next bugfix release will probably be 2.0.1.
## Automated binary releases
## Firmware binary releases
Every night our build-bot will build a new binary release: https://github.com/letscontrolit/ESPEasy/releases
Binary development releases are here: https://github.com/letscontrolit/ESPEasy/releases
The releases are named something like 'mega-01022018' (last number is the build date)
Depending on your needs, we release different types of files.
This uses version v2.0-20181001 as an example.
Depending on your needs, we release different types of files:
Firmware name | Hardware | Included plugins |
----------------------------------------------|-------------------------|-----------------------------|
ESPEasy_v2.0-20181001_normal_ESP8266_1024.bin | ESP8266 with 1Mb flash | Stable |
ESPEasy_v2.0-20181001_test_ESP8266_1024.bin | ESP8266 with 1Mb flash | Stable + Test |
ESPEasy_v2.0-20181001_dev_ESP8266_1024.bin | ESP8266 with 1Mb flash | Stable + Test + Development |
ESPEasy_v2.0-20181001_normal_ESP8266_4096.bin | ESP8266 with 4Mb flash | Stable |
ESPEasy_v2.0-20181001_test_ESP8266_4096.bin | ESP8266 with 4Mb flash | Stable + Test |
ESPEasy_v2.0-20181001_dev_ESP8266_4096.bin | ESP8266 with 4Mb flash | Stable + Test + Development |
ESPEasy_v2.0-20181001_normal_ESP8285_1024.bin | ESP8285 with 1Mb flash | Stable |
ESPEasy_v2.0-20181001_test_ESP8285_1024.bin | ESP8285 with 1Mb flash | Stable + Test |
ESPEasy_v2.0-20181001_dev_ESP8285_1024.bin | ESP8285 with 1Mb flash | Stable + Test + Development |
ESPEasy_mega-01022018_normal_ESP8266_1024.bin | ESP8266 with 1Mb flash | Stable |
ESPEasy_mega-01022018_test_ESP8266_1024.bin | ESP8266 with 1Mb flash | Stable + Test |
ESPEasy_mega-01022018_dev_ESP8266_1024.bin | ESP8266 with 1Mb flash | Stable + Test + Development |
ESPEasy_mega-01022018_normal_ESP8266_4096.bin | ESP8266 with 4Mb flash | Stable |
ESPEasy_mega-01022018_test_ESP8266_4096.bin | ESP8266 with 4Mb flash | Stable + Test |
ESPEasy_mega-01022018_dev_ESP8266_4096.bin | ESP8266 with 4Mb flash | Stable + Test + Development |
ESPEasy_mega-01022018_normal_ESP8285_1024.bin | ESP8285 with 1Mb flash | Stable |
ESPEasy_mega-01022018_test_ESP8285_1024.bin | ESP8285 with 1Mb flash | Stable + Test |
ESPEasy_mega-01022018_dev_ESP8285_1024.bin | ESP8285 with 1Mb flash | Stable + Test + Development |
## More info
+14 -25
View File
@@ -1,32 +1,24 @@
#!/bin/bash
VERSION=$(git describe)
echo "Creating release archives for $VERSION ..."
#binaries
#Naming convention:
# ESP_Easy_[github version]_[plugin set]_[chip type]_[flash memory].bin
#ESP_Easy_v[version]-[build type]-dev[dev number]-ESP[chip type]-[size].bin
#cp .pioenvs/mini_512/firmware.bin dist/"ESPEasy_$VERSION""_mini_512.bin"
for ENV in \
normal_ESP8266_1024 \
normal_ESP8266_4096 \
normal_ESP8285_1024 \
normal_ESP8266_1024_DOUT \
test_ESP8266_1024\
test_ESP8266_4096\
test_ESP8266_4096_VCC\
test_ESP8285_1024\
dev_ESP8266_1024\
dev_ESP8266_4096\
dev_ESP8285_1024\
dev_ESP8266PUYA_1024\
dev_ESP8266PUYA_1024_VCC;\
do
echo
echo "### Deploying environment $ENV for version $VERSION"
BIN=.pioenvs/$ENV/firmware.bin
cp $BIN dist/"ESP_Easy_$VERSION""_$ENV.bin"
done
cp .pioenvs/normal_ESP8266_1024/firmware.bin dist/"ESP_Easy_$VERSION""_normal_ESP8266_1024.bin"
cp .pioenvs/normal_ESP8266_4096/firmware.bin dist/"ESP_Easy_$VERSION""_normal_ESP8266_4096.bin"
cp .pioenvs/normal_ESP8285_1024/firmware.bin dist/"ESP_Easy_$VERSION""_normal_ESP8285_1024.bin"
cp .pioenvs/test_ESP8266_1024/firmware.bin dist/"ESP_Easy_$VERSION""_test_ESP8266_1024.bin"
cp .pioenvs/test_ESP8266_4096/firmware.bin dist/"ESP_Easy_$VERSION""_test_ESP8266_4096.bin"
cp .pioenvs/test_ESP8285_1024/firmware.bin dist/"ESP_Easy_$VERSION""_test_ESP8285_1024.bin"
cp .pioenvs/dev_ESP8266_1024/firmware.bin dist/"ESP_Easy_$VERSION""_dev_ESP8266_1024.bin"
cp .pioenvs/dev_ESP8266_4096/firmware.bin dist/"ESP_Easy_$VERSION""_dev_ESP8266_4096.bin"
cp .pioenvs/dev_ESP8285_1024/firmware.bin dist/"ESP_Easy_$VERSION""_dev_ESP8285_1024.bin"
#create a source structure that is the same as the original ESPEasy project (and works with the howto on the wiki)
rm -rf dist/Source 2>/dev/null
@@ -36,7 +28,4 @@ cp -r src dist/Source/
cp platformio.ini dist/Source/
cd dist
echo
echo "### Creating zip archive"
zip ../ESPEasy_$VERSION.zip -r .
+128 -691
View File
@@ -1,702 +1,139 @@
-------------------------------------------------
Changes in release v2.0-20180510 (since v2.0-20180322)
Changes in release mega-20180104 (since mega-01032018)
-------------------------------------------------
Release date: Thu May 10 04:00:27 CEST 2018
Gijs Noorlander (1):
Revert "Update _P045_MPU6050.ino"
Maarten Paauw (1):
Update _P045_MPU6050.ino
-------------------------------------------------
Changes in release v2.0-20180322 (since v2.0-20180321)
-------------------------------------------------
Release date: Thu Mar 22 04:00:24 CET 2018
Bartlomiej Zimon (3):
- P012 fix command interpretation
- P023 fix command interpretation
- P048 fetch params only when needed
TD-er (4):
- P035 move strings to flash
[wifi] Make more robust checks and increase timeout
[Memory] parseTemplate did not check if markers were found
[WiFi] Take much more time for initial WiFi connect during setup
s0170071 (1):
Serial WD crash
-------------------------------------------------
Changes in release v2.0-20180321 (since v2.0-20180320)
-------------------------------------------------
Release date: Wed Mar 21 04:00:21 CET 2018
Gijs Noorlander (1):
[merge issue] Forgotten #endif in merge
Unknown (1):
[wifi] Setup with factory settings could not complete
-------------------------------------------------
Changes in release v2.0-20180320 (since v2.0-20180319)
-------------------------------------------------
Release date: Tue Mar 20 04:00:23 CET 2018
Unknown (2):
Revert "Merge pull request #1116 from TD-er/feature/allow_own_defaults"
[issue #1097] WiFi connect with deepsleep enabled trigger watchdog reset
es-ka (1):
Fix wiring description for SN75176 transceiver
-------------------------------------------------
Changes in release v2.0-20180319 (since v2.0-20180316)
-------------------------------------------------
Release date: Mon Mar 19 04:00:24 CET 2018
Gijs Noorlander (6):
Add download button for current rule set (#1102)
- add encoder write command #1086 (#1103)
Changed so that running all tasks immediately with deep sleep enabled… (#1110)
Merge pull request #1112 from uzi18/fix-p073
Merge pull request #1114 from TD-er/feature/wifi_details_json
Merge pull request #1118 from TD-er/bugfix/mqtt_publish_after_deep_sleep
Unknown (3):
Merge pull request #1113 from TD-er/feature/reduce_impact_wifi_disconnect
Merge pull request #1116 from TD-er/feature/allow_own_defaults
[merge] MIssing #endif due to merging.
-------------------------------------------------
Changes in release v2.0-20180316 (since v2.0-20180313)
-------------------------------------------------
Release date: Fri Mar 16 04:00:23 CET 2018
Bartlomiej Zimon (1):
Merge branch 'mega' of github.com:letscontrolit/ESPEasy into mega
Gijs Noorlander (3):
MCP3221 allow values for calibration (#1073)
[issue #1066] Fix Webserver handle_control (#1079)
Fixed multi instance problem on SHT3x #433 (#1081)
Unknown (5):
- move all structs from ESPEasy.ino into header file
[v2.0 split globals] Base split on v2.0 version of ESPEasy.ino
[issue #1057] AM PM display issue
[issue #993] variable in MQTT subscribe topic
[issue #951] Changed System#Initialized => System#Wake
mvdbro (4):
#893 part1, send messages
Custom controller GUI option
#893, part 2 receiving
Rules fix
-------------------------------------------------
Changes in release v2.0-20180313 (since v2.0-20180312)
-------------------------------------------------
Release date: Tue Mar 13 04:00:23 CET 2018
Bartlomiej Zimon (2):
- fix for #1065
- remove double trimm()
-------------------------------------------------
Changes in release v2.0-20180312 (since v2.0-20180311)
-------------------------------------------------
Release date: Mon Mar 12 04:00:19 CET 2018
Unknown (3):
[issue #1039 ] Change CSS to show topmost SSID on large screens
[webserver] Improve chunked transfer
Rule Engine minor fix and added dev debugging
-------------------------------------------------
Changes in release v2.0-20180311 (since v2.0-20180310)
-------------------------------------------------
Release date: Sun Mar 11 04:00:19 CET 2018
Unknown (10):
Improve flash read performance
Add read buffer to rule processing to speedup parsing
Final ruleset speed-up
[AM/PM] Am/Pm notation doesn't have '0' hours
Update P07 Plugin
[P073] Remove tm1637_bitDelay()
[deepsleep] Make sure the 'shortcut' of running all services when sleep enabled
[OLED] fix drawProgressBar
[DNS lookup] Controllers sometimes try to connect to 0.0.0.0
[issue #1039] Topmost SSID are covered on mobile Browser
mvdbro (1):
Rule Engine, stop waisting time on non matching rules
-------------------------------------------------
Changes in release v2.0-20180310 (since v2.0-20180309)
-------------------------------------------------
Release date: Sat Mar 10 04:00:20 CET 2018
Unknown (2):
Move plugin init before WiFi init
[Conversions] Use more decimals in conversions and add AM/PM for time.
-------------------------------------------------
Changes in release v2.0-20180309 (since v2.0-20180307)
-------------------------------------------------
Release date: Fri Mar 9 04:00:22 CET 2018
Unknown (3):
[Rule Events] Add a number of events to handle in rules and awake timer
[issue #1015] Add other simple conversions like Celsius to Fahrenheit, etc.
[issue #1015] Add other simple conversions like Celsius to Fahrenheit, etc.
-------------------------------------------------
Changes in release v2.0-20180307 (since v2.0-20180306)
-------------------------------------------------
Release date: Wed Mar 7 04:00:21 CET 2018
Gijs Noorlander (1):
[CSS] Quick fix for smaller displays (#1026)
Unknown (1):
[issue #1012] Removed Content-Length header + improved webserver speed
-------------------------------------------------
Changes in release v2.0-20180306 (since v2.0-20180305)
-------------------------------------------------
Release date: Tue Mar 6 04:00:17 CET 2018
Gijs Noorlander (1):
Fixes P073 plugin for latest TM1637 based 7 segments displays modules (#996) (#1022)
-------------------------------------------------
Changes in release v2.0-20180305 (since v2.0-20180304b)
-------------------------------------------------
Release date: Mon Mar 5 04:00:20 CET 2018
Unknown (2):
[issue #528] Set DOUT flash mode for all 1M builds
[issue #1003 ] Add conversion of wind direction to string
-------------------------------------------------
Changes in release v2.0-20180304b (since v2.0-20180304)
-------------------------------------------------
Release date: Sun Mar 4 18:20:49 CET 2018
Edwin Eefting (1):
dont build in silent mode to prevent travis timeouts
-------------------------------------------------
Changes in release v2.0-20180304 (since v2.0-20180303)
-------------------------------------------------
Release date: Sun Mar 4 04:00:19 CET 2018
Gijs Noorlander (2):
Merge pull request #1000 from uzi18/test3 (more comparisions in IF condition)
_P072_HDC1080 allow to send values to the controllers (#999)
Unknown (2):
[issue #993] Add %unit% variable in MQTT subscribe topic
[issue #892 ] Only use sensor type when really needed
-------------------------------------------------
Changes in release v2.0-20180303 (since v2.0-20180302)
-------------------------------------------------
Release date: Sat Mar 3 04:00:19 CET 2018
Unknown (5):
revert json to non-chunking #988 from s0170071/mega
[issue #293] json output nan values not double quoted
Add Task device type to json by @s0170071
[Issue #827] MQTT not using proper case for %sysname% variable.
Add AND/OR to rules & prevent unwanted case changes in strings (#994)
-------------------------------------------------
Changes in release v2.0-20180302 (since v2.0-20180228)
-------------------------------------------------
Release date: Fri Mar 2 04:00:21 CET 2018
Bartłomiej Zimoń (4):
provide System@Sleep event (#875)
add format #O to templates to show OFF/ON instead 0/1 (#949)
fix #964, add timeStringToSeconds and use it to compare time conditions (#965)
add format #O to templates to show OFF/ON instead 0/1 (#949)
Gijs Noorlander (1):
Merge pull request #983 from kahvm/mega
Unknown (4):
[issue #914] _P053_PMSx003 Dust Sensor looses sync
[issue #914] Check first 2 bytes of packet
[Build error fix] Must-keep-focus-when-pressing-buttons...
[webserver] Layout of code to improve readability
mvdbro (1):
Rule wildcard option on literal events
s0170071 (1):
Add Factory Reset button to web interface (#954)
-------------------------------------------------
Changes in release v2.0-20180228 (since v2.0-20180227)
-------------------------------------------------
Release date: Wed Feb 28 04:00:19 CET 2018
Gijs Noorlander (2):
[issue #966] Add %sysweekday% and %sysweekday_s% (#973)
[issue #968] Use template parser for OLED commands (#974)
-------------------------------------------------
Changes in release v2.0-20180227 (since v2.0-20180226)
-------------------------------------------------
Release date: Tue Feb 27 04:00:22 CET 2018
Edwin Eefting (2):
[test suite] changes from mega to 2.0
[test suite] changes from mega to 2.0
Gijs Noorlander (1):
[BuildError] StreamingBuffer code cleanup + fix order member initialize (#961)
-------------------------------------------------
Changes in release v2.0-20180226 (since v2.0-20180221)
-------------------------------------------------
Release date: Mon Feb 26 04:00:21 CET 2018
Bartłomiej Zimoń (1):
provide System@Sleep event (#875) (#931)
Edwin Eefting (1):
device page doesnt need next/previous page buttons anymore
Gijs Noorlander (6):
[MQTT] LWT "Connected" message doesn't have the retained flag (#925)
[v2.0] Added Vcc-binaries to deploy process #933 (#935)
[v2.0 merge] 2kwebserver_merge_to_mega #929 (#934)
[v2.0] Use ESPeasySoftwareSerial (#936)
[timeouts] Improve response when hosts are not reachable (#939)
[2k Webserver] Proper initialisation of StreamingBuffer members. (#941)
Unknown (1):
[ping lib] Added ping library
s0170071 (2):
V20 Webserver@LowMemory
Update WebServer.ino
-------------------------------------------------
Changes in release v2.0-20180221 (since v2.0-20180220)
-------------------------------------------------
Release date: Wed Feb 21 04:00:20 CET 2018
Edwin Eefting (1):
apply PUYA patch to all available frameworks
Gijs Noorlander (1):
[issue #899 ] Backport of DHT22 implementation on Mega (#913)
-------------------------------------------------
Changes in release v2.0-20180220 (since v2.0-20180219)
-------------------------------------------------
Release date: Tue Feb 20 04:00:19 CET 2018
Edwin Eefting (1):
SENSOR_TYPE_TEMP_BARO changed, was probably implemented incorrectly before
Gijs Noorlander (3):
[isue #877] Add VCC enable firmware file to release list (#894)
[Cleanup] Move String manipulating functions to single file (#895)
[issue #893] Fix globalSync not working when no controllers active (#896)
Unknown (3):
[issue #847] Fix last letter of command is cut in OpenHAB MQTT
[Event Log] Add event name to event processing time log
[issue #899] DHT22 readings not received
-------------------------------------------------
Changes in release v2.0-20180219 (since v2.0-20180218)
-------------------------------------------------
Release date: Mon Feb 19 04:00:19 CET 2018
Gijs Noorlander (2):
[issue #885] MAC address as system variable (#887)
[issue #890] Split overlap for both Domoticz controllers to helper (#891)
-------------------------------------------------
Changes in release v2.0-20180218 (since v2.0-20180217)
-------------------------------------------------
Release date: Sun Feb 18 04:00:11 CET 2018
Gijs Noorlander (1):
[issue #847 ] OpenHAB MQTT rewrite topic parser (#886)
-------------------------------------------------
Changes in release v2.0-20180217 (since v2.0-20180214)
-------------------------------------------------
Release date: Sat Feb 17 04:00:18 CET 2018
Gijs Noorlander (4):
[issue 866] Try to stop logging to serial when serial is not read. (#868)
[issue #853] Favicon.ico (#874)
[OLED Framed] ESP Easy logo (#876)
[issue #869] Added 'LWT' to last will topic and improved CPU load (#883)
-------------------------------------------------
Changes in release v2.0-20180214 (since v2.0-20180213)
-------------------------------------------------
Release date: Wed Feb 14 04:00:21 CET 2018
Edwin Eefting (3):
workaround for PUYA flash chips with write issues #650
travis build fix for PUYA
updated deploy script for PUYA
Gijs Noorlander (1):
[v2.0] Blynk controller (#865)
-------------------------------------------------
Changes in release v2.0-20180213 (since v2.0-20180212)
-------------------------------------------------
Release date: Tue Feb 13 04:00:20 CET 2018
Gijs Noorlander (8):
[#804] Degree symbol for non-framed OLED display (#835)
[issue #839] Add command support for setting contrast for OLED Framed (#841)
[P001 Switch] Fix a mixup in previous fix for switch (#845)
[v2.0] Fix compile errors on ESP32 (#848)
Bugfix/oled framed less memory (#859)
Formatting user vars (re-do of PR#482) + enabled check OpenHabMQTT (#851)
[issue #825] Change labels and password form for Thingspeak controller (#849)
[MQTT] Allow for background tests while waiting for wifi (#860)
soif (1):
P012 - Fix/handle lines exceeding LCD width + allow to clear line b4 print (#852)
-------------------------------------------------
Changes in release v2.0-20180212 (since v2.0-20180209)
-------------------------------------------------
Release date: Mon Feb 12 04:00:22 CET 2018
Gijs Noorlander (1):
[Issue #831] Use DOUT flash mode (#834)
soif (1):
Add Device Name in /json page (#815)
-------------------------------------------------
Changes in release v2.0-20180209 (since v2.0-20180206)
-------------------------------------------------
Release date: Fri Feb 9 04:00:26 CET 2018
wdonker (1):
Add trigger for rulesprocessing (#826)
-------------------------------------------------
Changes in release v2.0-20180206 (since v2.0-20180203)
-------------------------------------------------
Release date: Tue Feb 6 05:00:21 CET 2018
Gijs Noorlander (3):
Backport OLED framed from mega + support special characters (#818)
[issue #817] Added mail header to SMTP (#820)
[issue #727] Proper user interface to set DST rules (#823)
soif (1):
All Advanced Settings as 'DEFAULT_' Defines (#813)
-------------------------------------------------
Changes in release v2.0-20180203 (since v2.0-20180202)
-------------------------------------------------
Release date: Sat Feb 3 05:00:20 CET 2018
Grovkillen (1):
Update README.md
-------------------------------------------------
Changes in release v2.0-20180202 (since v2.0-20180130)
-------------------------------------------------
Release date: Fri Feb 2 05:00:23 CET 2018
DatuX (2):
Update README.md
Update README.md
Gijs Noorlander (3):
[issue #794] Add longpulse_ms command (#796)
[v2.0] Resource friendly string replacement (#798)
[issue #739] Reconnect MQTT when Unit Name has changed. (#803)
soif (5):
Fixes invalid '/json' page output format : DateTimeString is now correctly quoted (#802)
Fix Syslog : include Hosname instead of Unit Number - now RFC3164 compliant (#805)
Allows to define the IP address when in AP Mode (#806)
Custom define file (#807)
Json page also Shows Git Build (#808)
-------------------------------------------------
Changes in release v2.0-20180130 (since v2.0-20180126)
-------------------------------------------------
Release date: Tue Jan 30 05:00:23 CET 2018
Edwin Eefting (1):
forgot to commit last framed oled display fix
Gijs Noorlander (3):
Bugfix/issue 740 allow mqtt as controller 2 3 (#785)
[#784] Add %rssi% as system variable (#786)
[Log] Clean up of log routines and more intuitive log level input (#788)
-------------------------------------------------
Changes in release v2.0-20180126 (since v2.0-20180124)
-------------------------------------------------
Release date: Fri Jan 26 05:00:22 CET 2018
Gijs Noorlander (3):
[issue #759] Disable Senseair ABC due to firmware issues (#771)
[V2.0] Allow IRremoteESP8266 to be built with core 2.4.0 (#773)
Update _C007.ino (#774) (#776)
-------------------------------------------------
Changes in release v2.0-20180124 (since v2.0-20180123)
-------------------------------------------------
Release date: Wed Jan 24 05:00:19 CET 2018
Edwin Eefting (1):
fix #718. also update display on save and removed graphical boot logo to conserve space. also fixes #713. (web interface will be non repsonsive during scrolling now, but there is no easy fix for that)
Gijs Noorlander (1):
[issue #758] P029 MQTT helper does not log anymore (#764)
-------------------------------------------------
Changes in release v2.0-20180123 (since v2.0-20180122)
-------------------------------------------------
Release date: Tue Jan 23 05:00:20 CET 2018
Edwin Eefting (5):
test suite: now possible to run all tests at once. fixes
test suite: espcli can now do stuff for all configured nodes
clear custom task and controller settings when selecting a different device or protocol. replaces #762 . fixes #721
added easy reboot warning and function to work around several issues
request mainpage when checking if reboot is complete
Gijs Noorlander (1):
Central function for system variable replacement (#757)
-------------------------------------------------
Changes in release v2.0-20180122 (since v2.0-20180121)
-------------------------------------------------
Release date: Mon Jan 22 05:00:19 CET 2018
Gijs Noorlander (2):
[issue #745] Set IPaddress to 0.0.0.0 when read from empty string (#754)
[#732] Only process P029 MQTT helper when enabled (#743)
-------------------------------------------------
Changes in release v2.0-20180121 (since v2.0-20180120)
-------------------------------------------------
Release date: Sun Jan 21 05:00:12 CET 2018
Edwin Eefting (5):
test suite: generelized controller testing in test005
cleaned up nodo logging. fixed domotics SENSOR_TYPE_WIND inconsistency
test suite: fixed issues, started working on nodo
test suite: lots of refactoring and fixing
test suite: fixes. testing boot gpio states
-------------------------------------------------
Changes in release v2.0-20180120 (since v2.0-20180119)
-------------------------------------------------
Release date: Sat Jan 20 05:00:12 CET 2018
Edwin Eefting (2):
added QUAD to c002. fixed getBearing and SENSOR_TYPE_WIND.
test suite: started on testcase to test all sensor types via the dummy plugin
-------------------------------------------------
Changes in release v2.0-20180119 (since v2.0-20180118)
-------------------------------------------------
Release date: Fri Jan 19 05:00:18 CET 2018
Edwin Eefting (2):
test suite domoticz mqtt + found few fixmes
test suite: added dht22
-------------------------------------------------
Changes in release v2.0-20180118 (since v2.0-20180116)
-------------------------------------------------
Release date: Thu Jan 18 05:00:19 CET 2018
Edwin Eefting (1):
refactoring test suite controller stuff
Gijs Noorlander (2):
[issue 733] Fix for negative values on MQTT import (#735)
[issue 728] Proper reconnect for MQTT controllers (#737)
-------------------------------------------------
Changes in release v2.0-20180116 (since v2.0-20180113)
-------------------------------------------------
Release date: Tue Jan 16 05:00:21 CET 2018
Edwin Eefting (3):
fixed custom build path
made test resumable and importable
now supports powercycle to test for bugs like #719
Gijs Noorlander (1):
[AutoDST] Added Auto DST (Bugfix/v2.0 issue569) (#726)
-------------------------------------------------
Changes in release v2.0-20180113 (since v2.0-20180112)
-------------------------------------------------
Release date: Sat Jan 13 05:00:20 CET 2018
Edwin Eefting (5):
release bot fixes
dont make same release twice
dont make same release twice
ESPEasy v2.0 only supports compiling under arduino core 2.3.0 to prevent issues like #705 when people use Arduino IDE to compile with arduino core 2.4.0
testsuite: working on generic http/mqtt controller emulatior receiving
-------------------------------------------------
Changes in release v2.0-20180112 (since v2.0-20180111)
-------------------------------------------------
Release date: Fri Jan 12 01:56:54 CET 2018
Edwin Eefting (4):
added http server emulation and domotics http to testsuite
first http domoticz test works
testsuite requirements
fixed releasebot issues with multiple branches
Gijs Noorlander (2):
[Issue 699] Incorrect shown device name (#700)
[v2.0 #470] Do not send invalid values to a controller (#701)
-------------------------------------------------
Changes in release v2.0-20180111 (since mega-20180111)
-------------------------------------------------
Release date: Thu Jan 11 05:00:18 CET 2018
-------------------------------------------------
Changes in release v2.0-20180110 (since mega-20180104)
-------------------------------------------------
Release date: Wed Jan 10 16:14:23 CET 2018
Release date: Thu Jan 4 03:13:01 UTC 2018
ESPEasy release bot (1):
added releasebot to v2.0 branch
changed date format of nightly builds
Edwin Eefting (5):
changed readme title
readme updates
actually ignore MQTT messages that are too big.
moved mqtt stuff outside of backgroundtasks(). fixes #683 in my test scenario
fixed plugin id of "Communication - Kamstrup Multical 401". (accidental octal notation)
Gijs Noorlander (4):
[switch] Fixed switch behavior and default settings. (#675)
[Flash info] Detailed flash information (#678)
Bugfix/v2.0 crash switch (#682)
[Adafruit MPR121] Change deprecated name setThreshholds to setThresholds (#685)
-------------------------------------------------
Changes in release mega-01032018 (since mega-01022018)
-------------------------------------------------
chunter1 (1):
ABC calibration feature added (#606)
Release date: Wed Jan 3 04:00:06 UTC 2018
Edwin Eefting (4):
updated readme to reflect new binary names
updated travis link to reflect v2.0
updated travis link to reflect v2.0
changed readme to reflect mega branch and automated builds
-------------------------------------------------
Changes in release mega-01022018 (since v2.0.0-dev13)
-------------------------------------------------
Release date: Tue Jan 2 23:32:50 UTC 2018
Alexander Schulz (1):
improvement: Configurable number of tasks for "Devices" page (TASKS_P…
BadWolf42 (1):
Dallas Plugin enhanced : no more "delay()" (#488)
Bartłomiej Zimoń (1):
Update _C002.ino (#645)
DaM (1):
[Domoticz HTTP] Compatibility fix for BMP280 (#636)
ESPEasy release bot (1):
created releasebot script
Edwin Eefting (12):
keep TASKS_PER_PAGE at default value of 4
fix plugin id (starting with a 0 makes it octal in c++ :( )
fix warnings
fixed bug in oled upstream lib
test fixes
smooth out testing code
esptest stuff
fix travis build errors. disable cpp checking for now
set lcd to NULL by default. #584
fix illegal string manipulations in PLUGIN_WRITE for some plugins. fixes #347 and #460
fix #588. parseTemplate() now only checks enabled taskes for [] macros
testing for ds18b20
GHolli (1):
Cosmetics: fixing typos. (#628)
Gijs Noorlander (11):
P028 to support both BME280 and BMP280 to reduce resource usage (#481)
Single function for format to user defined number decimals (#482)
OLED framed improve header footer (#495)
[SSD1306] Feature/oled 1306 library upgrade (#501)
[MH-Z19] Allow for B-version and add filtering (#525)
Support both SSD1306 and SH1106 OLED in OLED_Framed plugin (#509)
[LCD plugin] Added check of LCD object before dereferencing it (#584)
[P039 Thermocouple] Handling negative values and proper error logging (#586)
Reduce iRAM usage for plugins using SoftwareSerial (#631)
[Security] Add IP-based filtering to web interface and http-commands. (#653)
[SDS011] Allow the sensor to sleep to extend sensor lifetime (#668)
Grovkillen (5):
Added categories... (#552)
Changed bin file names to be more descriptive. (#597)
Move "TTP229 keypad" and "Encoder" plugin from "testing" to "normal" (#619)
Updated ESPTOOLS.exe from 0.4.6 to 0.4.12 (#627)
Updated "/pinstates" page: Made the plugin number column display "P001" instead of "1" and "P012" instead of "12".
M0ebiu5 (1):
P022_PCA9685 added change frequency - P038_NeoPixel added RGBW strips (SK6812) (#638)
Michael (2):
WebServer.ino: enhance handle_SDfilelist() (#507)
src/Hardware.ino: make it possible to use GPIO-0 (D3) as Pin_sd_cs (#508)
Sen Haerens (1):
Enhanced system info layout (#624)
SightofSilence (1):
Add System Variable for day, month and year / Fix for "Calculate" function to recognize minus-sign (#485)
SloMusti (1):
implemewnted web activity timer tracker (#462)
Tomasz Torcz (1):
retain MQTT LWT messages (#516)
denisfrench (1):
Set MQTT clientid to %sysname% +/- Settings.Unit (#431) (#436)
fensoft (1):
added #define FEATURE_SD (permit a flash size reduction of ~10k) (#568)
hatzlhoffer (1):
added new display size 128x32 (#545)
krikk (1):
added support for the TSL2591 Sensor based on Adafruit Library (#661)
mvdbro (8):
First preparations for ESP32
ESP32 IRAM/Deepsleep
ESP32 Rules/ADC/PWM
ESP32 fix FreeRAM reporting
ESP32 Enabled OTA
ESP32 fix UDP instability
ESP32 fixed chunked HTTP transfer
Fix #599
papperone (3):
Plugin 073 - 7-segment display plugin TM1637/MAX7219
Update _P073_7DGT.ino (#553)
deleted GPIO notes referring to 75HC595 not supported (#591)
paulv888 (1):
usesID = true (#666)
s0170071 (2):
split IP addrress (#605)
fix chunking (#649)
sakinit (1):
Fix p1 wifi gateway module (#587)
-------------------------------------------------
BIN
View File
Binary file not shown.
+10 -10
View File
@@ -1,16 +1,16 @@
/***************************************************
/***************************************************
This is a library for the MPR121 I2C 12-chan Capacitive Sensor
Designed specifically to work with the MPR121 sensor from Adafruit
----> https://www.adafruit.com/products/1982
These sensors use I2C to communicate, 2+ pins are required to
These sensors use I2C to communicate, 2+ pins are required to
interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, all text above must be included in any redistribution
****************************************************/
@@ -21,26 +21,26 @@ Adafruit_MPR121::Adafruit_MPR121() {
boolean Adafruit_MPR121::begin(uint8_t i2caddr) {
Wire.begin();
_i2caddr = i2caddr;
// soft reset
writeRegister(MPR121_SOFTRESET, 0x63);
delay(1);
for (uint8_t i=0; i<0x7F; i++) {
// Serial.print("$"); Serial.print(i, HEX);
// Serial.print("$"); Serial.print(i, HEX);
// Serial.print(": 0x"); Serial.println(readRegister8(i));
}
writeRegister(MPR121_ECR, 0x0);
uint8_t c = readRegister8(MPR121_CONFIG2);
if (c != 0x24) return false;
setThresholds(12, 6);
setThreshholds(12, 6);
writeRegister(MPR121_MHDR, 0x01);
writeRegister(MPR121_NHDR, 0x01);
writeRegister(MPR121_NCLR, 0x0E);
+154
View File
@@ -0,0 +1,154 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software< /span>
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* Update by K. Townsend (Adafruit Industries) for lighter typedefs, and
* extended sensor support to include color, voltage and current */
#ifndef _ADAFRUIT_SENSOR_H
#define _ADAFRUIT_SENSOR_H
#if ARDUINO >= 100
#include "Arduino.h"
#include "Print.h"
#else
#include "WProgram.h"
#endif
/* Intentionally modeled after sensors.h in the Android API:
* https://github.com/android/platform_hardware_libhardware/blob/master/include/hardware/sensors.h */
/* Constants */
#define SENSORS_GRAVITY_EARTH (9.80665F) /**< Earth's gravity in m/s^2 */
#define SENSORS_GRAVITY_MOON (1.6F) /**< The moon's gravity in m/s^2 */
#define SENSORS_GRAVITY_SUN (275.0F) /**< The sun's gravity in m/s^2 */
#define SENSORS_GRAVITY_STANDARD (SENSORS_GRAVITY_EARTH)
#define SENSORS_MAGFIELD_EARTH_MAX (60.0F) /**< Maximum magnetic field on Earth's surface */
#define SENSORS_MAGFIELD_EARTH_MIN (30.0F) /**< Minimum magnetic field on Earth's surface */
#define SENSORS_PRESSURE_SEALEVELHPA (1013.25F) /**< Average sea level pressure is 1013.25 hPa */
#define SENSORS_DPS_TO_RADS (0.017453293F) /**< Degrees/s to rad/s multiplier */
#define SENSORS_GAUSS_TO_MICROTESLA (100) /**< Gauss to micro-Tesla multiplier */
/** Sensor types */
typedef enum
{
SENSOR_TYPE_ACCELEROMETER = (1), /**< Gravity + linear acceleration */
SENSOR_TYPE_MAGNETIC_FIELD = (2),
SENSOR_TYPE_ORIENTATION = (3),
SENSOR_TYPE_GYROSCOPE = (4),
SENSOR_TYPE_LIGHT = (5),
SENSOR_TYPE_PRESSURE = (6),
SENSOR_TYPE_PROXIMITY = (8),
SENSOR_TYPE_GRAVITY = (9),
SENSOR_TYPE_LINEAR_ACCELERATION = (10), /**< Acceleration not including gravity */
SENSOR_TYPE_ROTATION_VECTOR = (11),
SENSOR_TYPE_RELATIVE_HUMIDITY = (12),
SENSOR_TYPE_AMBIENT_TEMPERATURE = (13),
SENSOR_TYPE_VOLTAGE = (15),
SENSOR_TYPE_CURRENT = (16),
SENSOR_TYPE_COLOR = (17)
} sensors_type_t;
/** struct sensors_vec_s is used to return a vector in a common format. */
typedef struct {
union {
float v[3];
struct {
float x;
float y;
float z;
};
/* Orientation sensors */
struct {
float roll; /**< Rotation around the longitudinal axis (the plane body, 'X axis'). Roll is positive and increasing when moving downward. -90°<=roll<=90° */
float pitch; /**< Rotation around the lateral axis (the wing span, 'Y axis'). Pitch is positive and increasing when moving upwards. -180°<=pitch<=180°) */
float heading; /**< Angle between the longitudinal axis (the plane body) and magnetic north, measured clockwise when viewing from the top of the device. 0-359° */
};
};
int8_t status;
uint8_t reserved[3];
} sensors_vec_t;
/** struct sensors_color_s is used to return color data in a common format. */
typedef struct {
union {
float c[3];
/* RGB color space */
struct {
float r; /**< Red component */
float g; /**< Green component */
float b; /**< Blue component */
};
};
uint32_t rgba; /**< 24-bit RGBA value */
} sensors_color_t;
/* Sensor event (36 bytes) */
/** struct sensor_event_s is used to provide a single sensor event in a common format. */
typedef struct
{
int32_t version; /**< must be sizeof(struct sensors_event_t) */
int32_t sensor_id; /**< unique sensor identifier */
int32_t type; /**< sensor type */
int32_t reserved0; /**< reserved */
int32_t timestamp; /**< time is in milliseconds */
union
{
float data[4];
sensors_vec_t acceleration; /**< acceleration values are in meter per second per second (m/s^2) */
sensors_vec_t magnetic; /**< magnetic vector values are in micro-Tesla (uT) */
sensors_vec_t orientation; /**< orientation values are in degrees */
sensors_vec_t gyro; /**< gyroscope values are in rad/s */
float temperature; /**< temperature is in degrees centigrade (Celsius) */
float distance; /**< distance in centimeters */
float light; /**< light in SI lux units */
float pressure; /**< pressure in hectopascal (hPa) */
float relative_humidity; /**< relative humidity in percent */
float current; /**< current in milliamps (mA) */
float voltage; /**< voltage in volts (V) */
sensors_color_t color; /**< color in RGB component values */
};
} sensors_event_t;
/* Sensor details (40 bytes) */
/** struct sensor_s is used to describe basic information about a specific sensor. */
typedef struct
{
char name[12]; /**< sensor name */
int32_t version; /**< version of the hardware + driver */
int32_t sensor_id; /**< unique sensor identifier */
int32_t type; /**< this sensor's type (ex. SENSOR_TYPE_LIGHT) */
float max_value; /**< maximum value of this sensor's value in SI units */
float min_value; /**< minimum value of this sensor's value in SI units */
float resolution; /**< smallest difference between two values reported by this sensor */
int32_t min_delay; /**< min delay in microseconds between events. zero = not a constant rate */
} sensor_t;
class Adafruit_Sensor {
public:
// Constructor(s)
Adafruit_Sensor() {}
virtual ~Adafruit_Sensor() {}
// These must be defined by the subclass
virtual void enableAutoRange(bool enabled) {};
virtual bool getEvent(sensors_event_t*) = 0;
virtual void getSensor(sensor_t*) = 0;
private:
bool _autoRange;
};
#endif
+221
View File
@@ -0,0 +1,221 @@
# Adafruit Unified Sensor Driver #
Many small embedded systems exist to collect data from sensors, analyse the data, and either take an appropriate action or send that sensor data to another system for processing.
One of the many challenges of embedded systems design is the fact that parts you used today may be out of production tomorrow, or system requirements may change and you may need to choose a different sensor down the road.
Creating new drivers is a relatively easy task, but integrating them into existing systems is both error prone and time consuming since sensors rarely use the exact same units of measurement.
By reducing all data to a single **sensors\_event\_t** 'type' and settling on specific, **standardised SI units** for each sensor family the same sensor types return values that are comparable with any other similar sensor. This enables you to switch sensor models with very little impact on the rest of the system, which can help mitigate some of the risks and problems of sensor availability and code reuse.
The unified sensor abstraction layer is also useful for data-logging and data-transmission since you only have one well-known type to log or transmit over the air or wire.
## Unified Sensor Drivers ##
The following drivers are based on the Adafruit Unified Sensor Driver:
**Accelerometers**
- [Adafruit\_ADXL345](https://github.com/adafruit/Adafruit_ADXL345)
- [Adafruit\_LSM303DLHC](https://github.com/adafruit/Adafruit_LSM303DLHC)
- [Adafruit\_MMA8451\_Library](https://github.com/adafruit/Adafruit_MMA8451_Library)
**Gyroscope**
- [Adafruit\_L3GD20\_U](https://github.com/adafruit/Adafruit_L3GD20_U)
**Light**
- [Adafruit\_TSL2561](https://github.com/adafruit/Adafruit_TSL2561)
- [Adafruit\_TSL2591\_Library](https://github.com/adafruit/Adafruit_TSL2591_Library)
**Magnetometers**
- [Adafruit\_LSM303DLHC](https://github.com/adafruit/Adafruit_LSM303DLHC)
- [Adafruit\_HMC5883\_Unified](https://github.com/adafruit/Adafruit_HMC5883_Unified)
**Barometric Pressure**
- [Adafruit\_BMP085\_Unified](https://github.com/adafruit/Adafruit_BMP085_Unified)
- [Adafruit\_BMP183\_Unified\_Library](https://github.com/adafruit/Adafruit_BMP183_Unified_Library)
**Humidity & Temperature**
- [DHT-sensor-library](https://github.com/adafruit/DHT-sensor-library)
**Orientation**
- [Adafruit_BNO055](https://github.com/adafruit/Adafruit_BNO055)
## How Does it Work? ##
Any driver that supports the Adafruit unified sensor abstraction layer will implement the Adafruit\_Sensor base class. There are two main typedefs and one enum defined in Adafruit_Sensor.h that are used to 'abstract' away the sensor details and values:
**Sensor Types (sensors\_type\_t)**
These pre-defined sensor types are used to properly handle the two related typedefs below, and allows us determine what types of units the sensor uses, etc.
```
/** Sensor types */
typedef enum
{
SENSOR_TYPE_ACCELEROMETER = (1),
SENSOR_TYPE_MAGNETIC_FIELD = (2),
SENSOR_TYPE_ORIENTATION = (3),
SENSOR_TYPE_GYROSCOPE = (4),
SENSOR_TYPE_LIGHT = (5),
SENSOR_TYPE_PRESSURE = (6),
SENSOR_TYPE_PROXIMITY = (8),
SENSOR_TYPE_GRAVITY = (9),
SENSOR_TYPE_LINEAR_ACCELERATION = (10),
SENSOR_TYPE_ROTATION_VECTOR = (11),
SENSOR_TYPE_RELATIVE_HUMIDITY = (12),
SENSOR_TYPE_AMBIENT_TEMPERATURE = (13),
SENSOR_TYPE_VOLTAGE = (15),
SENSOR_TYPE_CURRENT = (16),
SENSOR_TYPE_COLOR = (17)
} sensors_type_t;
```
**Sensor Details (sensor\_t)**
This typedef describes the specific capabilities of this sensor, and allows us to know what sensor we are using beneath the abstraction layer.
```
/* Sensor details (40 bytes) */
/** struct sensor_s is used to describe basic information about a specific sensor. */
typedef struct
{
char name[12];
int32_t version;
int32_t sensor_id;
int32_t type;
float max_value;
float min_value;
float resolution;
int32_t min_delay;
} sensor_t;
```
The individual fields are intended to be used as follows:
- **name**: The sensor name or ID, up to a maximum of twelve characters (ex. "MPL115A2")
- **version**: The version of the sensor HW and the driver to allow us to differentiate versions of the board or driver
- **sensor\_id**: A unique sensor identifier that is used to differentiate this specific sensor instance from any others that are present on the system or in the sensor network
- **type**: The sensor type, based on **sensors\_type\_t** in sensors.h
- **max\_value**: The maximum value that this sensor can return (in the appropriate SI unit)
- **min\_value**: The minimum value that this sensor can return (in the appropriate SI unit)
- **resolution**: The smallest difference between two values that this sensor can report (in the appropriate SI unit)
- **min\_delay**: The minimum delay in microseconds between two sensor events, or '0' if there is no constant sensor rate
**Sensor Data/Events (sensors\_event\_t)**
This typedef is used to return sensor data from any sensor supported by the abstraction layer, using standard SI units and scales.
```
/* Sensor event (36 bytes) */
/** struct sensor_event_s is used to provide a single sensor event in a common format. */
typedef struct
{
int32_t version;
int32_t sensor_id;
int32_t type;
int32_t reserved0;
int32_t timestamp;
union
{
float data[4];
sensors_vec_t acceleration;
sensors_vec_t magnetic;
sensors_vec_t orientation;
sensors_vec_t gyro;
float temperature;
float distance;
float light;
float pressure;
float relative_humidity;
float current;
float voltage;
sensors_color_t color;
};
} sensors_event_t;
```
It includes the following fields:
- **version**: Contain 'sizeof(sensors\_event\_t)' to identify which version of the API we're using in case this changes in the future
- **sensor\_id**: A unique sensor identifier that is used to differentiate this specific sensor instance from any others that are present on the system or in the sensor network (must match the sensor\_id value in the corresponding sensor\_t enum above!)
- **type**: the sensor type, based on **sensors\_type\_t** in sensors.h
- **timestamp**: time in milliseconds when the sensor value was read
- **data[4]**: An array of four 32-bit values that allows us to encapsulate any type of sensor data via a simple union (further described below)
**Required Functions**
In addition to the two standard types and the sensor type enum, all drivers based on Adafruit_Sensor must also implement the following two functions:
```
bool getEvent(sensors_event_t*);
```
Calling this function will populate the supplied sensors\_event\_t reference with the latest available sensor data. You should call this function as often as you want to update your data.
```
void getSensor(sensor_t*);
```
Calling this function will provide some basic information about the sensor (the sensor name, driver version, min and max values, etc.
**Standardised SI values for sensors\_event\_t**
A key part of the abstraction layer is the standardisation of values on SI units of a particular scale, which is accomplished via the data[4] union in sensors\_event\_t above. This 16 byte union includes fields for each main sensor type, and uses the following SI units and scales:
- **acceleration**: values are in **meter per second per second** (m/s^2)
- **magnetic**: values are in **micro-Tesla** (uT)
- **orientation**: values are in **degrees**
- **gyro**: values are in **rad/s**
- **temperature**: values in **degrees centigrade** (Celsius)
- **distance**: values are in **centimeters**
- **light**: values are in **SI lux** units
- **pressure**: values are in **hectopascal** (hPa)
- **relative\_humidity**: values are in **percent**
- **current**: values are in **milliamps** (mA)
- **voltage**: values are in **volts** (V)
- **color**: values are in 0..1.0 RGB channel luminosity and 32-bit RGBA format
## The Unified Driver Abstraction Layer in Practice ##
Using the unified sensor abstraction layer is relatively easy once a compliant driver has been created.
Every compliant sensor can now be read using a single, well-known 'type' (sensors\_event\_t), and there is a standardised way of interrogating a sensor about its specific capabilities (via sensor\_t).
An example of reading the [TSL2561](https://github.com/adafruit/Adafruit_TSL2561) light sensor can be seen below:
```
Adafruit_TSL2561 tsl = Adafruit_TSL2561(TSL2561_ADDR_FLOAT, 12345);
...
/* Get a new sensor event */
sensors_event_t event;
tsl.getEvent(&event);
/* Display the results (light is measured in lux) */
if (event.light)
{
Serial.print(event.light); Serial.println(" lux");
}
else
{
/* If event.light = 0 lux the sensor is probably saturated
and no reliable data could be generated! */
Serial.println("Sensor overload");
}
```
Similarly, we can get the basic technical capabilities of this sensor with the following code:
```
sensor_t sensor;
sensor_t sensor;
tsl.getSensor(&sensor);
/* Display the sensor details */
Serial.println("------------------------------------");
Serial.print ("Sensor: "); Serial.println(sensor.name);
Serial.print ("Driver Ver: "); Serial.println(sensor.version);
Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id);
Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" lux");
Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" lux");
Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" lux");
Serial.println("------------------------------------");
Serial.println("");
```
+9
View File
@@ -0,0 +1,9 @@
name=Adafruit Unified Sensor
version=1.0.2
author=Adafruit <info@adafruit.com>
maintainer=Adafruit <info@adafruit.com>
sentence=Required for all Adafruit Unified Sensor based libraries.
paragraph=A unified sensor abstraction layer used by many Adafruit sensor libraries.
category=Sensors
url=https://github.com/adafruit/Adafruit_Sensor
architectures=*
+46
View File
@@ -0,0 +1,46 @@
Thank you for opening an issue on an Adafruit Arduino library repository. To
improve the speed of resolution please review the following guidelines and
common troubleshooting steps below before creating the issue:
- **Do not use GitHub issues for troubleshooting projects and issues.** Instead use
the forums at http://forums.adafruit.com to ask questions and troubleshoot why
something isn't working as expected. In many cases the problem is a common issue
that you will more quickly receive help from the forum community. GitHub issues
are meant for known defects in the code. If you don't know if there is a defect
in the code then start with troubleshooting on the forum first.
- **If following a tutorial or guide be sure you didn't miss a step.** Carefully
check all of the steps and commands to run have been followed. Consult the
forum if you're unsure or have questions about steps in a guide/tutorial.
- **For Arduino projects check these very common issues to ensure they don't apply**:
- For uploading sketches or communicating with the board make sure you're using
a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes
very hard to tell the difference between a data and charge cable! Try using the
cable with other devices or swapping to another cable to confirm it is not
the problem.
- **Be sure you are supplying adequate power to the board.** Check the specs of
your board and plug in an external power supply. In many cases just
plugging a board into your computer is not enough to power it and other
peripherals.
- **Double check all soldering joints and connections.** Flakey connections
cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints.
- **Ensure you are using an official Arduino or Adafruit board.** We can't
guarantee a clone board will have the same functionality and work as expected
with this code and don't support them.
If you're sure this issue is a defect in the code and checked the steps above
please fill in the following fields to provide enough troubleshooting information.
You may delete the guideline and text above to just leave the following details:
- Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE**
- Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO
VERSION HERE**
- List the steps to reproduce the problem below (if possible attach a sketch or
copy the sketch code in too): **LIST REPRO STEPS BELOW**
+26
View File
@@ -0,0 +1,26 @@
Thank you for creating a pull request to contribute to Adafruit's GitHub code!
Before you open the request please review the following guidelines and tips to
help it be more easily integrated:
- **Describe the scope of your change--i.e. what the change does and what parts
of the code were modified.** This will help us understand any risks of integrating
the code.
- **Describe any known limitations with your change.** For example if the change
doesn't apply to a supported platform of the library please mention it.
- **Please run any tests or examples that can exercise your modified code.** We
strive to not break users of the code and running tests/examples helps with this
process.
Thank you again for contributing! We will try to test and integrate the change
as soon as we can, but be aware we have many GitHub repositories to manage and
can't immediately respond to every request. There is no need to bump or check in
on a pull request (it will clutter the discussion of the request).
Also don't be worried if the request is closed or not integrated--sometimes the
priorities of Adafruit's GitHub code (education, ease of use) might not match the
priorities of the pull request. Don't fret, the open source community thrives on
forks and GitHub makes it easy to keep your changes in a forked repo.
After reviewing the guidelines above you can delete this text from the pull request.
+504
View File
@@ -0,0 +1,504 @@
/**************************************************************************/
/*!
@file Adafruit_TSL2591.cpp
@author KT0WN (adafruit.com)
This is a library for the Adafruit TSL2591 breakout board
This library works with the Adafruit TSL2591 breakout
----> https://www.adafruit.com/products/1980
Check out the links above for our tutorials and wiring diagrams
These chips use I2C to communicate
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
@section LICENSE
Software License Agreement (BSD License)
Copyright (c) 2014 Adafruit Industries
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holders nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/
#if defined(ESP8266) || defined(ESP32)
#include <pgmspace.h>
#else
#include <avr/pgmspace.h>
#endif
#if defined(__AVR__)
#include <util/delay.h>
#endif
#include <stdlib.h>
#include "Adafruit_TSL2591.h"
Adafruit_TSL2591::Adafruit_TSL2591(int32_t sensorID)
{
_initialized = false;
_integration = TSL2591_INTEGRATIONTIME_100MS;
_gain = TSL2591_GAIN_MED;
_sensorID = sensorID;
// we cant do wire initialization till later, because we havent loaded Wire yet
}
boolean Adafruit_TSL2591::begin(void)
{
Wire.begin();
/*
for (uint8_t i=0; i<0x20; i++)
{
uint8_t id = read8(0x12);
Serial.print("$"); Serial.print(i, HEX);
Serial.print(" = 0x"); Serial.println(read8(i), HEX);
}
*/
uint8_t id = read8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_DEVICE_ID);
if (id == 0x50 )
{
// Serial.println("Found Adafruit_TSL2591");
}
else
{
return false;
}
_initialized = true;
// Set default integration time and gain
setTiming(_integration);
setGain(_gain);
// Note: by default, the device is in power down mode on bootup
disable();
return true;
}
void Adafruit_TSL2591::enable(void)
{
if (!_initialized)
{
if (!begin())
{
return;
}
}
// Enable the device by setting the control bit to 0x01
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_ENABLE, TSL2591_ENABLE_POWERON | TSL2591_ENABLE_AEN | TSL2591_ENABLE_AIEN | TSL2591_ENABLE_NPIEN);
}
void Adafruit_TSL2591::disable(void)
{
if (!_initialized)
{
if (!begin())
{
return;
}
}
// Disable the device by setting the control bit to 0x00
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_ENABLE, TSL2591_ENABLE_POWEROFF);
}
void Adafruit_TSL2591::setGain(tsl2591Gain_t gain)
{
if (!_initialized)
{
if (!begin())
{
return;
}
}
enable();
_gain = gain;
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CONTROL, _integration | _gain);
disable();
}
tsl2591Gain_t Adafruit_TSL2591::getGain()
{
return _gain;
}
void Adafruit_TSL2591::setTiming(tsl2591IntegrationTime_t integration)
{
if (!_initialized)
{
if (!begin())
{
return;
}
}
enable();
_integration = integration;
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CONTROL, _integration | _gain);
disable();
}
tsl2591IntegrationTime_t Adafruit_TSL2591::getTiming()
{
return _integration;
}
float Adafruit_TSL2591::calculateLuxf(uint16_t ch0, uint16_t ch1)
{
float atime, again;
float cpl, lux1, lux2, lux;
uint32_t chan0, chan1;
// Check for overflow conditions first
if ((ch0 == 0xFFFF) | (ch1 == 0xFFFF))
{
// Signal an overflow
return 0;
}
// Note: This algorithm is based on preliminary coefficients
// provided by AMS and may need to be updated in the future
switch (_integration)
{
case TSL2591_INTEGRATIONTIME_100MS :
atime = 100.0F;
break;
case TSL2591_INTEGRATIONTIME_200MS :
atime = 200.0F;
break;
case TSL2591_INTEGRATIONTIME_300MS :
atime = 300.0F;
break;
case TSL2591_INTEGRATIONTIME_400MS :
atime = 400.0F;
break;
case TSL2591_INTEGRATIONTIME_500MS :
atime = 500.0F;
break;
case TSL2591_INTEGRATIONTIME_600MS :
atime = 600.0F;
break;
default: // 100ms
atime = 100.0F;
break;
}
switch (_gain)
{
case TSL2591_GAIN_LOW :
again = 1.0F;
break;
case TSL2591_GAIN_MED :
again = 25.0F;
break;
case TSL2591_GAIN_HIGH :
again = 428.0F;
break;
case TSL2591_GAIN_MAX :
again = 9876.0F;
break;
default:
again = 1.0F;
break;
}
// cpl = (ATIME * AGAIN) / DF
cpl = (atime * again) / TSL2591_LUX_DF;
lux1 = (((float) ch0 - (float) ch1)) * (1.0F - ((float) ch1 / (float) ch0)) / cpl;//( (float)ch0 - (TSL2591_LUX_COEFB * (float)ch1) ) / cpl;
lux2 = ((TSL2591_LUX_COEFC * (float) ch0) - (TSL2591_LUX_COEFD * (float) ch1)) / cpl;
lux = lux1 > lux2 ? lux1 : lux2;
// Alternate lux calculation
//lux = ( (float)ch0 - ( 1.7F * (float)ch1 ) ) / cpl;
// Signal I2C had no errors
return lux;
}
uint32_t Adafruit_TSL2591::calculateLux(uint16_t ch0, uint16_t ch1)
{
return (uint32_t) calculateLuxf(ch0, ch1);
}
uint32_t Adafruit_TSL2591::getFullLuminosity (void)
{
if (!_initialized)
{
if (!begin())
{
return 0;
}
}
// Enable the device
enable();
// Wait x ms for ADC to complete
for (uint8_t d=0; d<=_integration; d++)
{
delay(120);
}
uint32_t x;
uint16_t y;
y |= read16(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CHAN0_LOW);
x = read16(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CHAN1_LOW);
x <<= 16;
x |= y;
disable();
return x;
}
uint16_t Adafruit_TSL2591::getLuminosity (uint8_t channel)
{
uint32_t x = getFullLuminosity();
if (channel == TSL2591_FULLSPECTRUM)
{
// Reads two byte value from channel 0 (visible + infrared)
return (x & 0xFFFF);
}
else if (channel == TSL2591_INFRARED)
{
// Reads two byte value from channel 1 (infrared)
return (x >> 16);
}
else if (channel == TSL2591_VISIBLE)
{
// Reads all and subtracts out just the visible!
return ( (x & 0xFFFF) - (x >> 16));
}
// unknown channel!
return 0;
}
void Adafruit_TSL2591::registerInterrupt(uint16_t lowerThreshold, uint16_t upperThreshold)
{
if (!_initialized)
{
if (!begin())
{
return;
}
}
enable();
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_THRESHOLD_NPAILTL, lowerThreshold);
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_THRESHOLD_NPAILTH, lowerThreshold >> 8);
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_THRESHOLD_NPAIHTL, upperThreshold);
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_THRESHOLD_NPAIHTH, upperThreshold >> 8);
disable();
}
void Adafruit_TSL2591::registerInterrupt(uint16_t lowerThreshold, uint16_t upperThreshold, tsl2591Persist_t persist)
{
if (!_initialized)
{
if (!begin())
{
return;
}
}
enable();
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_PERSIST_FILTER, persist);
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_THRESHOLD_AILTL, lowerThreshold);
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_THRESHOLD_AILTH, lowerThreshold >> 8);
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_THRESHOLD_AIHTL, upperThreshold);
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_THRESHOLD_AIHTH, upperThreshold >> 8);
disable();
}
void Adafruit_TSL2591::clearInterrupt()
{
if (!_initialized)
{
if (!begin())
{
return;
}
}
enable();
write8(TSL2591_CLEAR_INT);
disable();
}
uint8_t Adafruit_TSL2591::getStatus()
{
if (!_initialized)
{
if (!begin())
{
return 0;
}
}
// Enable the device
enable();
uint8_t x;
x = read8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_DEVICE_STATUS);
disable();
return x;
}
uint8_t Adafruit_TSL2591::read8(uint8_t reg)
{
uint8_t x;
Wire.beginTransmission(TSL2591_ADDR);
#if ARDUINO >= 100
Wire.write(reg);
#else
Wire.send(reg);
#endif
Wire.endTransmission();
Wire.requestFrom(TSL2591_ADDR, 1);
#if ARDUINO >= 100
x = Wire.read();
#else
x = Wire.receive();
#endif
// while (! Wire.available());
// return Wire.read();
return x;
}
uint16_t Adafruit_TSL2591::read16(uint8_t reg)
{
uint16_t x;
uint16_t t;
Wire.beginTransmission(TSL2591_ADDR);
#if ARDUINO >= 100
Wire.write(reg);
#else
Wire.send(reg);
#endif
Wire.endTransmission();
Wire.requestFrom(TSL2591_ADDR, 2);
#if ARDUINO >= 100
t = Wire.read();
x = Wire.read();
#else
t = Wire.receive();
x = Wire.receive();
#endif
x <<= 8;
x |= t;
return x;
}
void Adafruit_TSL2591::write8 (uint8_t reg, uint8_t value)
{
Wire.beginTransmission(TSL2591_ADDR);
#if ARDUINO >= 100
Wire.write(reg);
Wire.write(value);
#else
Wire.send(reg);
Wire.send(value);
#endif
Wire.endTransmission();
}
void Adafruit_TSL2591::write8 (uint8_t reg)
{
Wire.beginTransmission(TSL2591_ADDR);
#if ARDUINO >= 100
Wire.write(reg);
#else
Wire.send(reg);
#endif
Wire.endTransmission();
}
/**************************************************************************/
/*!
@brief Gets the most recent sensor event
*/
/**************************************************************************/
bool Adafruit_TSL2591::getEvent(sensors_event_t *event)
{
uint16_t ir, full;
uint32_t lum = getFullLuminosity();
/* Early silicon seems to have issues when there is a sudden jump in */
/* light levels. :( To work around this for now sample the sensor 2x */
lum = getFullLuminosity();
ir = lum >> 16;
full = lum & 0xFFFF;
/* Clear the event */
memset(event, 0, sizeof(sensors_event_t));
event->version = sizeof(sensors_event_t);
event->sensor_id = _sensorID;
event->type = SENSOR_TYPE_LIGHT;
event->timestamp = millis();
/* Calculate the actual lux value */
/* 0 = sensor overflow (too much light) */
event->light = calculateLux(full, ir);
return true;
}
/**************************************************************************/
/*!
@brief Gets the sensor_t data
*/
/**************************************************************************/
void Adafruit_TSL2591::getSensor(sensor_t *sensor)
{
/* Clear the sensor_t object */
memset(sensor, 0, sizeof(sensor_t));
/* Insert the sensor name in the fixed length char array */
strncpy (sensor->name, "TSL2591", sizeof(sensor->name) - 1);
sensor->name[sizeof(sensor->name)- 1] = 0;
sensor->version = 1;
sensor->sensor_id = _sensorID;
sensor->type = SENSOR_TYPE_LIGHT;
sensor->min_delay = 0;
sensor->max_value = 88000.0;
sensor->min_value = 0.0;
sensor->resolution = 1.0;
}
+187
View File
@@ -0,0 +1,187 @@
/**************************************************************************/
/*!
@file Adafruit_TSL2591.h
@author KT0WN (adafruit.com)
This is a library for the Adafruit TSL2591 breakout board
This library works with the Adafruit TSL2591 breakout
----> https://www.adafruit.com/products/1980
Check out the links above for our tutorials and wiring diagrams
These chips use I2C to communicate
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
@section LICENSE
Software License Agreement (BSD License)
Copyright (c) 2014 Adafruit Industries
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holders nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/
#ifndef _TSL2591_H_
#define _TSL2591_H_
#if ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
#include <Adafruit_Sensor.h>
#include <Wire.h>
#define TSL2591_VISIBLE (2) // channel 0 - channel 1
#define TSL2591_INFRARED (1) // channel 1
#define TSL2591_FULLSPECTRUM (0) // channel 0
#define TSL2591_ADDR (0x29)
#define TSL2591_READBIT (0x01)
#define TSL2591_COMMAND_BIT (0xA0) // 1010 0000: bits 7 and 5 for 'command normal'
#define TSL2591_CLEAR_INT (0xE7)
#define TSL2591_TEST_INT (0xE4)
#define TSL2591_WORD_BIT (0x20) // 1 = read/write word (rather than byte)
#define TSL2591_BLOCK_BIT (0x10) // 1 = using block read/write
#define TSL2591_ENABLE_POWEROFF (0x00)
#define TSL2591_ENABLE_POWERON (0x01)
#define TSL2591_ENABLE_AEN (0x02) // ALS Enable. This field activates ALS function. Writing a one activates the ALS. Writing a zero disables the ALS.
#define TSL2591_ENABLE_AIEN (0x10) // ALS Interrupt Enable. When asserted permits ALS interrupts to be generated, subject to the persist filter.
#define TSL2591_ENABLE_NPIEN (0x80) // No Persist Interrupt Enable. When asserted NP Threshold conditions will generate an interrupt, bypassing the persist filter
#define TSL2591_LUX_DF (408.0F)
#define TSL2591_LUX_COEFB (1.64F) // CH0 coefficient
#define TSL2591_LUX_COEFC (0.59F) // CH1 coefficient A
#define TSL2591_LUX_COEFD (0.86F) // CH2 coefficient B
enum
{
TSL2591_REGISTER_ENABLE = 0x00,
TSL2591_REGISTER_CONTROL = 0x01,
TSL2591_REGISTER_THRESHOLD_AILTL = 0x04, // ALS low threshold lower byte
TSL2591_REGISTER_THRESHOLD_AILTH = 0x05, // ALS low threshold upper byte
TSL2591_REGISTER_THRESHOLD_AIHTL = 0x06, // ALS high threshold lower byte
TSL2591_REGISTER_THRESHOLD_AIHTH = 0x07, // ALS high threshold upper byte
TSL2591_REGISTER_THRESHOLD_NPAILTL = 0x08, // No Persist ALS low threshold lower byte
TSL2591_REGISTER_THRESHOLD_NPAILTH = 0x09, // etc
TSL2591_REGISTER_THRESHOLD_NPAIHTL = 0x0A,
TSL2591_REGISTER_THRESHOLD_NPAIHTH = 0x0B,
TSL2591_REGISTER_PERSIST_FILTER = 0x0C,
TSL2591_REGISTER_PACKAGE_PID = 0x11,
TSL2591_REGISTER_DEVICE_ID = 0x12,
TSL2591_REGISTER_DEVICE_STATUS = 0x13,
TSL2591_REGISTER_CHAN0_LOW = 0x14,
TSL2591_REGISTER_CHAN0_HIGH = 0x15,
TSL2591_REGISTER_CHAN1_LOW = 0x16,
TSL2591_REGISTER_CHAN1_HIGH = 0x17
};
typedef enum
{
TSL2591_INTEGRATIONTIME_100MS = 0x00,
TSL2591_INTEGRATIONTIME_200MS = 0x01,
TSL2591_INTEGRATIONTIME_300MS = 0x02,
TSL2591_INTEGRATIONTIME_400MS = 0x03,
TSL2591_INTEGRATIONTIME_500MS = 0x04,
TSL2591_INTEGRATIONTIME_600MS = 0x05,
}
tsl2591IntegrationTime_t;
typedef enum
{
// bit 7:4: 0
TSL2591_PERSIST_EVERY = 0x00, // Every ALS cycle generates an interrupt
TSL2591_PERSIST_ANY = 0x01, // Any value outside of threshold range
TSL2591_PERSIST_2 = 0x02, // 2 consecutive values out of range
TSL2591_PERSIST_3 = 0x03, // 3 consecutive values out of range
TSL2591_PERSIST_5 = 0x04, // 5 consecutive values out of range
TSL2591_PERSIST_10 = 0x05, // 10 consecutive values out of range
TSL2591_PERSIST_15 = 0x06, // 15 consecutive values out of range
TSL2591_PERSIST_20 = 0x07, // 20 consecutive values out of range
TSL2591_PERSIST_25 = 0x08, // 25 consecutive values out of range
TSL2591_PERSIST_30 = 0x09, // 30 consecutive values out of range
TSL2591_PERSIST_35 = 0x0A, // 35 consecutive values out of range
TSL2591_PERSIST_40 = 0x0B, // 40 consecutive values out of range
TSL2591_PERSIST_45 = 0x0C, // 45 consecutive values out of range
TSL2591_PERSIST_50 = 0x0D, // 50 consecutive values out of range
TSL2591_PERSIST_55 = 0x0E, // 55 consecutive values out of range
TSL2591_PERSIST_60 = 0x0F, // 60 consecutive values out of range
}
tsl2591Persist_t;
typedef enum
{
TSL2591_GAIN_LOW = 0x00, // low gain (1x)
TSL2591_GAIN_MED = 0x10, // medium gain (25x)
TSL2591_GAIN_HIGH = 0x20, // medium gain (428x)
TSL2591_GAIN_MAX = 0x30, // max gain (9876x)
}
tsl2591Gain_t;
class Adafruit_TSL2591 : public Adafruit_Sensor
{
public:
Adafruit_TSL2591(int32_t sensorID = -1);
boolean begin ( void );
void enable ( void );
void disable ( void );
void write8 ( uint8_t r);
void write8 ( uint8_t r, uint8_t v );
uint16_t read16 ( uint8_t reg );
uint8_t read8 ( uint8_t reg );
uint32_t calculateLux ( uint16_t ch0, uint16_t ch1 );
float calculateLuxf ( uint16_t ch0, uint16_t ch1 );
void setGain ( tsl2591Gain_t gain );
void setTiming ( tsl2591IntegrationTime_t integration );
uint16_t getLuminosity (uint8_t channel );
uint32_t getFullLuminosity ( );
tsl2591IntegrationTime_t getTiming();
tsl2591Gain_t getGain();
// Interrupt
void clearInterrupt(void);
void registerInterrupt(uint16_t lowerThreshold, uint16_t upperThreshold);
void registerInterrupt(uint16_t lowerThreshold, uint16_t upperThreshold, tsl2591Persist_t persist);
uint8_t getStatus();
/* Unified Sensor API Functions */
bool getEvent ( sensors_event_t* );
void getSensor ( sensor_t* );
private:
tsl2591IntegrationTime_t _integration;
tsl2591Gain_t _gain;
int32_t _sensorID;
boolean _initialized;
};
#endif
+9
View File
@@ -0,0 +1,9 @@
This is an Arduino library for the TSL2591 digital luminosity (light) sensors.
Pick one up at http://www.adafruit.com/products/1980
To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_TSL2591. Check that the Adafruit_TSL2591 folder contains Adafruit_TSL2591.cpp and Adafruit_TSL2591.h
Place the Adafruit_TSL2591 library folder your <arduinosketchfolder>/libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE.
You'll also need the Adafruit_Sensor library from https://github.com/adafruit/Adafruit_Sensor
@@ -0,0 +1,200 @@
/* TSL2591 Digital Light Sensor */
/* Dynamic Range: 600M:1 */
/* Maximum Lux: 88K */
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_TSL2591.h"
// Example for demonstrating the TSL2591 library - public domain!
// connect SCL to analog 5
// connect SDA to analog 4
// connect Vin to 3.3-5V DC
// connect GROUND to common ground
Adafruit_TSL2591 tsl = Adafruit_TSL2591(2591); // pass in a number for the sensor identifier (for your use later)
/**************************************************************************/
/*
Displays some basic information on this sensor from the unified
sensor API sensor_t type (see Adafruit_Sensor for more information)
*/
/**************************************************************************/
void displaySensorDetails(void)
{
sensor_t sensor;
tsl.getSensor(&sensor);
Serial.println(F("------------------------------------"));
Serial.print (F("Sensor: ")); Serial.println(sensor.name);
Serial.print (F("Driver Ver: ")); Serial.println(sensor.version);
Serial.print (F("Unique ID: ")); Serial.println(sensor.sensor_id);
Serial.print (F("Max Value: ")); Serial.print(sensor.max_value); Serial.println(F(" lux"));
Serial.print (F("Min Value: ")); Serial.print(sensor.min_value); Serial.println(F(" lux"));
Serial.print (F("Resolution: ")); Serial.print(sensor.resolution); Serial.println(F(" lux"));
Serial.println(F("------------------------------------"));
Serial.println(F(""));
delay(500);
}
/**************************************************************************/
/*
Configures the gain and integration time for the TSL2591
*/
/**************************************************************************/
void configureSensor(void)
{
// You can change the gain on the fly, to adapt to brighter/dimmer light situations
//tsl.setGain(TSL2591_GAIN_LOW); // 1x gain (bright light)
tsl.setGain(TSL2591_GAIN_MED); // 25x gain
// tsl.setGain(TSL2591_GAIN_HIGH); // 428x gain
// Changing the integration time gives you a longer time over which to sense light
// longer timelines are slower, but are good in very low light situtations!
tsl.setTiming(TSL2591_INTEGRATIONTIME_100MS); // shortest integration time (bright light)
// tsl.setTiming(TSL2591_INTEGRATIONTIME_200MS);
// tsl.setTiming(TSL2591_INTEGRATIONTIME_300MS);
// tsl.setTiming(TSL2591_INTEGRATIONTIME_400MS);
// tsl.setTiming(TSL2591_INTEGRATIONTIME_500MS);
// tsl.setTiming(TSL2591_INTEGRATIONTIME_600MS); // longest integration time (dim light)
/* Display the gain and integration time for reference sake */
Serial.println(F("------------------------------------"));
Serial.print (F("Gain: "));
tsl2591Gain_t gain = tsl.getGain();
switch(gain)
{
case TSL2591_GAIN_LOW:
Serial.println(F("1x (Low)"));
break;
case TSL2591_GAIN_MED:
Serial.println(F("25x (Medium)"));
break;
case TSL2591_GAIN_HIGH:
Serial.println(F("428x (High)"));
break;
case TSL2591_GAIN_MAX:
Serial.println(F("9876x (Max)"));
break;
}
Serial.print (F("Timing: "));
Serial.print((tsl.getTiming() + 1) * 100, DEC);
Serial.println(F(" ms"));
Serial.println(F("------------------------------------"));
Serial.println(F(""));
}
/**************************************************************************/
/*
Program entry point for the Arduino sketch
*/
/**************************************************************************/
void setup(void)
{
Serial.begin(9600);
Serial.println(F("Starting Adafruit TSL2591 Test!"));
if (tsl.begin())
{
Serial.println(F("Found a TSL2591 sensor"));
}
else
{
Serial.println(F("No sensor found ... check your wiring?"));
while (1);
}
/* Display some basic information on this sensor */
displaySensorDetails();
/* Configure the sensor */
configureSensor();
// Now we're ready to get readings ... move on to loop()!
}
/**************************************************************************/
/*
Shows how to perform a basic read on visible, full spectrum or
infrared light (returns raw 16-bit ADC values)
*/
/**************************************************************************/
void simpleRead(void)
{
// Simple data read example. Just read the infrared, fullspecrtrum diode
// or 'visible' (difference between the two) channels.
// This can take 100-600 milliseconds! Uncomment whichever of the following you want to read
uint16_t x = tsl.getLuminosity(TSL2591_VISIBLE);
//uint16_t x = tsl.getLuminosity(TSL2591_FULLSPECTRUM);
//uint16_t x = tsl.getLuminosity(TSL2591_INFRARED);
Serial.print(F("[ ")); Serial.print(millis()); Serial.print(F(" ms ] "));
Serial.print(F("Luminosity: "));
Serial.println(x, DEC);
}
/**************************************************************************/
/*
Show how to read IR and Full Spectrum at once and convert to lux
*/
/**************************************************************************/
void advancedRead(void)
{
// More advanced data read example. Read 32 bits with top 16 bits IR, bottom 16 bits full spectrum
// That way you can do whatever math and comparisons you want!
uint32_t lum = tsl.getFullLuminosity();
uint16_t ir, full;
ir = lum >> 16;
full = lum & 0xFFFF;
Serial.print(F("[ ")); Serial.print(millis()); Serial.print(F(" ms ] "));
Serial.print(F("IR: ")); Serial.print(ir); Serial.print(F(" "));
Serial.print(F("Full: ")); Serial.print(full); Serial.print(F(" "));
Serial.print(F("Visible: ")); Serial.print(full - ir); Serial.print(F(" "));
Serial.print(F("Lux: ")); Serial.println(tsl.calculateLux(full, ir));
}
/**************************************************************************/
/*
Performs a read using the Adafruit Unified Sensor API.
*/
/**************************************************************************/
void unifiedSensorAPIRead(void)
{
/* Get a new sensor event */
sensors_event_t event;
tsl.getEvent(&event);
/* Display the results (light is measured in lux) */
Serial.print(F("[ ")); Serial.print(event.timestamp); Serial.print(F(" ms ] "));
if ((event.light == 0) |
(event.light > 4294966000.0) |
(event.light <-4294966000.0))
{
/* If event.light = 0 lux the sensor is probably saturated */
/* and no reliable data could be generated! */
/* if event.light is +/- 4294967040 there was a float over/underflow */
Serial.println(F("Invalid data (adjust gain or timing)"));
}
else
{
Serial.print(event.light); Serial.println(F(" lux"));
}
}
/**************************************************************************/
/*
Arduino loop function, called once 'setup' is complete (your own code
should go here)
*/
/**************************************************************************/
void loop(void)
{
//simpleRead();
advancedRead();
// unifiedSensorAPIRead();
delay(500);
}
@@ -0,0 +1,229 @@
/* TSL2591 Digital Light Sensor, example with (simple) interrupt support */
/* Dynamic Range: 600M:1 */
/* Maximum Lux: 88K */
/* This example shows how the interrupt system on the TLS2591
* can be used to detect a meaningful change in light levels.
*
* Two thresholds can be set:
*
* Lower Threshold - Any light sample on CHAN0 below this value
* will trigger an interrupt
* Upper Threshold - Any light sample on CHAN0 above this value
* will trigger an interrupt
*
* If CHAN0 (full light) crosses below the low threshold specified,
* or above the higher threshold, an interrupt is asserted on the interrupt
* pin. The use of the HW pin is optional, though, since the change can
* also be detected in software by looking at the status byte via
* tsl.getStatus().
*
* An optional third parameter can be used in the .registerInterrupt
* function to indicate the number of samples that must stay outside
* the threshold window before the interrupt fires, providing some basic
* debouncing of light level data.
*
* For example, the following code will fire an interrupt on any and every
* sample outside the window threshold (meaning a sample below 100 or above
* 1500 on CHAN0 or FULL light):
*
* tsl.registerInterrupt(100, 1500, TSL2591_PERSIST_ANY);
*
* This code would require five consecutive changes before the interrupt
* fires though (see tls2591Persist_t in Adafruit_TLS2591.h for possible
* values):
*
* tsl.registerInterrupt(100, 1500, TSL2591_PERSIST_5);
*/
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_TSL2591.h"
// Example for demonstrating the TSL2591 library - public domain!
// connect SCL to analog 5
// connect SDA to analog 4
// connect Vin to 3.3-5V DC
// connect GROUND to common ground
// Interrupt thresholds and persistance
#define TLS2591_INT_THRESHOLD_LOWER (100)
#define TLS2591_INT_THRESHOLD_UPPER (1500)
//#define TLS2591_INT_PERSIST (TSL2591_PERSIST_ANY) // Fire on any valid change
#define TLS2591_INT_PERSIST (TSL2591_PERSIST_60) // Require at least 60 samples to fire
Adafruit_TSL2591 tsl = Adafruit_TSL2591(2591); // pass in a number for the sensor identifier (for your use later)
/**************************************************************************/
/*
Displays some basic information on this sensor from the unified
sensor API sensor_t type (see Adafruit_Sensor for more information)
*/
/**************************************************************************/
void displaySensorDetails(void)
{
sensor_t sensor;
tsl.getSensor(&sensor);
Serial.println("------------------------------------");
Serial.print ("Sensor: "); Serial.println(sensor.name);
Serial.print ("Driver Ver: "); Serial.println(sensor.version);
Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id);
Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" lux");
Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" lux");
Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" lux");
Serial.println("------------------------------------");
Serial.println("");
delay(500);
}
/**************************************************************************/
/*
Configures the gain and integration time for the TSL2591
*/
/**************************************************************************/
void configureSensor(void)
{
// You can change the gain on the fly, to adapt to brighter/dimmer light situations
//tsl.setGain(TSL2591_GAIN_LOW); // 1x gain (bright light)
tsl.setGain(TSL2591_GAIN_MED); // 25x gain
// tsl.setGain(TSL2591_GAIN_HIGH); // 428x gain
// Changing the integration time gives you a longer time over which to sense light
// longer timelines are slower, but are good in very low light situtations!
tsl.setTiming(TSL2591_INTEGRATIONTIME_100MS); // shortest integration time (bright light)
// tsl.setTiming(TSL2591_INTEGRATIONTIME_200MS);
// tsl.setTiming(TSL2591_INTEGRATIONTIME_300MS);
// tsl.setTiming(TSL2591_INTEGRATIONTIME_400MS);
// tsl.setTiming(TSL2591_INTEGRATIONTIME_500MS);
// tsl.setTiming(TSL2591_INTEGRATIONTIME_600MS); // longest integration time (dim light)
/* Display the gain and integration time for reference sake */
Serial.println("------------------------------------");
Serial.print ("Gain: ");
tsl2591Gain_t gain = tsl.getGain();
switch (gain)
{
case TSL2591_GAIN_LOW:
Serial.println("1x (Low)");
break;
case TSL2591_GAIN_MED:
Serial.println("25x (Medium)");
break;
case TSL2591_GAIN_HIGH:
Serial.println("428x (High)");
break;
case TSL2591_GAIN_MAX:
Serial.println("9876x (Max)");
break;
}
Serial.print ("Timing: ");
Serial.print((tsl.getTiming() + 1) * 100, DEC);
Serial.println(" ms");
Serial.println("------------------------------------");
Serial.println("");
/* Setup the SW interrupt to trigger between 100 and 1500 lux */
/* Threshold values are defined at the top of this sketch */
tsl.clearInterrupt();
tsl.registerInterrupt(TLS2591_INT_THRESHOLD_LOWER,
TLS2591_INT_THRESHOLD_UPPER,
TLS2591_INT_PERSIST);
/* Display the interrupt threshold window */
Serial.print("Interrupt Threshold Window: -");
Serial.print(TLS2591_INT_THRESHOLD_LOWER, DEC);
Serial.print(" to +");
Serial.println(TLS2591_INT_THRESHOLD_LOWER, DEC);
Serial.println("");
}
/**************************************************************************/
/*
Program entry point for the Arduino sketch
*/
/**************************************************************************/
void setup(void)
{
Serial.begin(9600);
// Enable this line for Flora, Zero and Feather boards with no FTDI chip
// Waits for the serial port to connect before sending data out
// while (!Serial) { delay(1); }
Serial.println("Starting Adafruit TSL2591 interrupt Test!");
if (tsl.begin())
{
Serial.println("Found a TSL2591 sensor");
}
else
{
Serial.println("No sensor found ... check your wiring?");
while (1);
}
/* Display some basic information on this sensor */
displaySensorDetails();
/* Configure the sensor (including the interrupt threshold) */
configureSensor();
// Now we're ready to get readings ... move on to loop()!
}
/**************************************************************************/
/*
Show how to read IR and Full Spectrum at once and convert to lux
*/
/**************************************************************************/
void advancedRead(void)
{
// More advanced data read example. Read 32 bits with top 16 bits IR, bottom 16 bits full spectrum
// That way you can do whatever math and comparisons you want!
uint32_t lum = tsl.getFullLuminosity();
uint16_t ir, full;
ir = lum >> 16;
full = lum & 0xFFFF;
Serial.print("[ "); Serial.print(millis()); Serial.print(" ms ] ");
Serial.print("IR: "); Serial.print(ir); Serial.print(" ");
Serial.print("Full: "); Serial.print(full); Serial.print(" ");
Serial.print("Visible: "); Serial.print(full - ir); Serial.print(" ");
Serial.print("Lux: "); Serial.println(tsl.calculateLux(full, ir));
}
void getStatus(void)
{
uint8_t x = tsl.getStatus();
// bit 4: ALS Interrupt occured
// bit 5: No-persist Interrupt occurence
if (x & 0x10) {
Serial.print("[ "); Serial.print(millis()); Serial.print(" ms ] ");
Serial.println("ALS Interrupt occured");
}
if (x & 0x20) {
Serial.print("[ "); Serial.print(millis()); Serial.print(" ms ] ");
Serial.println("No-persist Interrupt occured");
}
// Serial.print("[ "); Serial.print(millis()); Serial.print(" ms ] ");
Serial.print("Status: ");
Serial.println(x, BIN);
tsl.clearInterrupt();
}
/**************************************************************************/
/*
Arduino loop function, called once 'setup' is complete (your own code
should go here)
*/
/**************************************************************************/
void loop(void)
{
advancedRead();
getStatus();
delay(500);
}
+9
View File
@@ -0,0 +1,9 @@
name=Adafruit TSL2591 Library
version=1.0.2
author=Adafruit
maintainer=Adafruit <info@adafruit.com>
sentence=Library for the TSL2591 digital luminosity (light) sensors.
paragraph=Library for the TSL2591 digital luminosity (light) sensors.
category=Sensors
url=https://github.com/adafruit/Adafruit_TSL2591_Library
architectures=*
-456
View File
@@ -1,456 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
-40
View File
@@ -1,40 +0,0 @@
# ESP8266Ping
Let the ESP8266 ping a remote machine.
With this library an ESP8266 can ping a remote machine and know if it's reachable.
It provide some basic measurements on ping messages (avg response time).
## Usage
First, include the library in your sketch along with WiFi library:
```Arduino
#include <ESP8266WiFi.h>
#include <ESP8266Ping.h>
```
Next, simply call the `Ping.ping()` function
```Arduino
IPAddress ip (192, 168, 0, 1); // The remote ip to ping
bool ret = Ping.ping(ip);
```
`ret` will be true if the remote responded to pings, false if not reachable.
The library supports hostname too, just pass a string instead of the ip address:
```Arduino
bool ret = Ping.ping("www.google.com");
```
Additionally, the function accept a second integer parameter `count` that specify how many pings has to be sent:
```Arduino
bool ret = Ping.ping(ip_or_host, 10);
```
After `Ping.ping()` has been called, the average response time (in milliseconds) can be retrieved with
```Arduino
int avg_time_ms = Ping.averageTime();
```
@@ -1,43 +0,0 @@
/*
* This example show how to ping a remote machine using it's hostname
*/
#include <ESP8266WiFi.h>
#include <ESP8266Ping.h>
const char* ssid = "ssid";
const char* password = "passphrase";
const char* remote_host = "www.google.com";
void setup() {
Serial.begin(115200);
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.println("Connecting to WiFi");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(100);
Serial.print(".");
}
Serial.println();
Serial.print("WiFi connected with ip ");
Serial.println(WiFi.localIP());
Serial.print("Pinging host ");
Serial.println(remote_host);
if(Ping.ping(remote_host)) {
Serial.println("Success!!");
} else {
Serial.println("Error :(");
}
}
void loop() { }
@@ -1,44 +0,0 @@
/*
* With this library an ESP8266 can ping a remote machine and know if it's reachable.
* It provides some basic measurements on ping messages (avg response time).
*/
#include <ESP8266WiFi.h>
#include <ESP8266Ping.h>
const char* ssid = "ssid";
const char* password = "passphrase";
const IPAddress remote_ip(192, 168, 0, 1);
void setup() {
Serial.begin(115200);
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.println("Connecting to WiFi");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(100);
Serial.print(".");
}
Serial.println();
Serial.print("WiFi connected with ip ");
Serial.println(WiFi.localIP());
Serial.print("Pinging ip ");
Serial.println(remote_ip);
if(Ping.ping(remote_ip)) {
Serial.println("Success!!");
} else {
Serial.println("Error :(");
}
}
void loop() { }
-26
View File
@@ -1,26 +0,0 @@
#######################################
# Syntax Coloring Map For ESP8266Ping
#######################################
#######################################
# Library (KEYWORD3)
#######################################
ESP8266Ping KEYWORD3
#######################################
# Datatypes (KEYWORD1)
#######################################
Ping KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
ping KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
@@ -1,9 +0,0 @@
name=ESPEasy_ESP8266Ping
version=1.0
author=Daniele Colanardi
maintainer=Daniele Colanardi <dancol90@gmail.com>
sentence=Let the ESP8266 ping a remote machine.
paragraph=With this library an ESP8266 can ping a remote machine and know if it's reachable. It provide some basic measurements on ping messages (avg response time). Lib name renamed to avoid conflicts in Arduino IDE.
category=Communication
url=
architectures=esp8266
-59
View File
@@ -1,59 +0,0 @@
/*
ESP8266Ping - Ping library for ESP8266
Copyright (c) 2015 Daniele Colanardi. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ESP8266Ping_H
#define ESP8266Ping_H
#include <Arduino.h>
#include <ESP8266WiFi.h>
extern "C" {
#include <ping.h>
}
#ifdef ENABLE_DEBUG_PING
#define DEBUG_PING(...) Serial.printf(__VA_ARGS__)
#else
#define DEBUG_PING(...)
#endif
class PingClass {
public:
PingClass();
bool ping(IPAddress dest, byte count = 5);
bool ping(const char* host, byte count = 5);
int averageTime();
protected:
static void _ping_sent_cb(void *opt, void *pdata);
static void _ping_recv_cb(void *opt, void *pdata);
IPAddress _dest;
ping_option _options;
static byte _expected_count, _errors, _success;
static int _avg_time;
};
#include "ESP8266Ping.impl.h"
PingClass Ping;
#endif
@@ -1,111 +0,0 @@
/*
ESP8266Ping - Ping library for ESP8266
Copyright (c) 2015 Daniele Colanardi. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
extern "C" void esp_schedule();
extern "C" void esp_yield();
PingClass::PingClass() {}
bool PingClass::ping(IPAddress dest, byte count) {
_expected_count = count;
_errors = 0;
_success = 0;
_avg_time = 0;
memset(&_options, 0, sizeof(struct ping_option));
// Repeat count (how many time send a ping message to destination)
_options.count = count;
// Time interval between two ping (seconds??)
_options.coarse_time = 1;
// Destination machine
_options.ip = dest;
// Callbacks
_options.recv_function = reinterpret_cast<ping_recv_function>(&PingClass::_ping_recv_cb);
_options.sent_function = NULL; //reinterpret_cast<ping_sent_function>(&_ping_sent_cb);
// Let's go!
if(ping_start(&_options)) {
// Suspend till the process end
esp_yield();
}
return (_success > 0);
}
bool PingClass::ping(const char* host, byte count) {
IPAddress remote_addr;
if (WiFi.hostByName(host, remote_addr))
return ping(remote_addr, count);
return false;
}
int PingClass::averageTime() {
return _avg_time;
}
void PingClass::_ping_recv_cb(void *opt, void *resp) {
// Cast the parameters to get some usable info
ping_resp* ping_resp = reinterpret_cast<struct ping_resp*>(resp);
//ping_option* ping_opt = reinterpret_cast<struct ping_option*>(opt);
// Error or success?
if (ping_resp->ping_err == -1)
_errors++;
else {
_success++;
_avg_time += ping_resp->resp_time;
}
// Some debug info
DEBUG_PING(
"DEBUG: ping reply\n"
"\ttotal_count = %d \n"
"\tresp_time = %d \n"
"\tseqno = %d \n"
"\ttimeout_count = %d \n"
"\tbytes = %d \n"
"\ttotal_bytes = %d \n"
"\ttotal_time = %d \n"
"\tping_err = %d \n",
ping_resp->total_count, ping_resp->resp_time, ping_resp->seqno,
ping_resp->timeout_count, ping_resp->bytes, ping_resp->total_bytes,
ping_resp->total_time, ping_resp->ping_err
);
// Is it time to end?
// Don't using seqno because it does not increase on error
if (_success + _errors == _expected_count) {
_avg_time = _avg_time / _expected_count;
DEBUG_PING("Avg resp time %d ms\n", _avg_time);
// Done, return to main functiom
esp_schedule();
}
}
byte PingClass::_expected_count = 0;
byte PingClass::_errors = 0;
byte PingClass::_success = 0;
int PingClass::_avg_time = 0;
+4 -4
View File
@@ -93,8 +93,8 @@ bool ICACHE_FLASH_ATTR IRKelvinatorAC::getPower() {
// Set the temp. in deg C
void ICACHE_FLASH_ATTR IRKelvinatorAC::setTemp(uint8_t temp) {
temp = max(static_cast<uint8_t>(KELVINATOR_MIN_TEMP), temp);
temp = min(static_cast<uint8_t>(KELVINATOR_MAX_TEMP), temp);
temp = max(KELVINATOR_MIN_TEMP, temp);
temp = min(KELVINATOR_MAX_TEMP, temp);
remote_state[1] = (remote_state[1] & 0xF0U) | (temp - KELVINATOR_MIN_TEMP);
remote_state[9] = remote_state[1]; // Duplicate to the 2nd command chunk.
}
@@ -106,12 +106,12 @@ uint8_t ICACHE_FLASH_ATTR IRKelvinatorAC::getTemp() {
// Set the speed of the fan, 0-5, 0 is auto, 1-5 is the speed
void ICACHE_FLASH_ATTR IRKelvinatorAC::setFan(uint8_t fan) {
fan = min(static_cast<uint8_t>(KELVINATOR_FAN_MAX), fan); // Bounds check
fan = min(KELVINATOR_FAN_MAX, fan); // Bounds check
// Only change things if we need to.
if (fan != getFan()) {
// Set the basic fan values.
uint8_t fan_basic = min(static_cast<uint8_t>(KELVINATOR_BASIC_FAN_MAX), fan);
uint8_t fan_basic = min(KELVINATOR_BASIC_FAN_MAX, fan);
remote_state[0] = (remote_state[0] & KELVINATOR_BASIC_FAN_MASK) |
(fan_basic << KELVINATOR_FAN_OFFSET);
remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk.
+3 -3
View File
@@ -77,8 +77,8 @@ bool ICACHE_FLASH_ATTR IRMitsubishiAC::getPower() {
// Set the temp. in deg C
void ICACHE_FLASH_ATTR IRMitsubishiAC::setTemp(uint8_t temp) {
temp = max(static_cast<uint8_t>(MITSUBISHI_AC_MIN_TEMP), temp);
temp = min(static_cast<uint8_t>(MITSUBISHI_AC_MAX_TEMP), temp);
temp = max(MITSUBISHI_AC_MIN_TEMP, temp);
temp = min(MITSUBISHI_AC_MAX_TEMP, temp);
remote_state[7] = temp - MITSUBISHI_AC_MIN_TEMP;
}
@@ -136,7 +136,7 @@ void ICACHE_FLASH_ATTR IRMitsubishiAC::setMode(uint8_t mode) {
// Set the requested vane operation mode of the a/c unit.
void ICACHE_FLASH_ATTR IRMitsubishiAC::setVane(uint8_t mode) {
mode = max(mode, static_cast<uint8_t>(B111)); // bounds check
mode = max(mode, B111); // bounds check
mode |= B1000;
mode <<= 3;
remote_state[9] |= mode;
+7 -7
View File
@@ -155,7 +155,7 @@ void ICACHE_FLASH_ATTR IRsend::sendNEC (unsigned long data, int nbits,
// Footer
mark(NEC_BIT_MARK);
// Gap to next command.
space(max(0ul, NEC_MIN_COMMAND_LENGTH - usecs.elapsed()));
space(max(0, NEC_MIN_COMMAND_LENGTH - usecs.elapsed()));
// Optional command repeat sequence.
for (unsigned int i = 0; i < repeat; i++) {
@@ -164,7 +164,7 @@ void ICACHE_FLASH_ATTR IRsend::sendNEC (unsigned long data, int nbits,
space(NEC_RPT_SPACE);
mark(NEC_BIT_MARK);
// Gap till next command.
space(max(0ul, NEC_MIN_COMMAND_LENGTH - usecs.elapsed()));
space(max(0, NEC_MIN_COMMAND_LENGTH - usecs.elapsed()));
}
}
@@ -236,7 +236,7 @@ void ICACHE_FLASH_ATTR IRsend::sendSony(unsigned long data, int nbits,
// Footer
// The Sony protocol requires us to wait 45ms from start of a code to the
// start of the next one. A 10ms minimum gap is also required.
space(max(10000u, 45000 - usecs.elapsed()));
space(max(10000, 45000 - usecs.elapsed()));
}
// A space() is always performed last, so no need to turn off the LED.
}
@@ -367,7 +367,7 @@ void ICACHE_FLASH_ATTR IRsend::sendRCMM(uint32_t data, uint8_t nbits) {
mark(RCMM_BIT_MARK);
// Protocol requires us to wait at least RCMM_RPT_LENGTH usecs from the start
// or RCMM_MIN_GAP usecs.
space(max(RCMM_RPT_LENGTH - usecs.elapsed(), static_cast<uint32_t>(RCMM_MIN_GAP)));
space(max(RCMM_RPT_LENGTH - usecs.elapsed(), RCMM_MIN_GAP));
}
void ICACHE_FLASH_ATTR IRsend::sendPanasonic(unsigned int address,
@@ -415,7 +415,7 @@ void ICACHE_FLASH_ATTR IRsend::sendJVC(unsigned long data, int nbits,
// Footer
mark(JVC_BIT_MARK);
// Wait till the end of the repeat time window before we send another code.
space(max(0u, JVC_RPT_LENGTH - usecs.elapsed()));
space(max(0, JVC_RPT_LENGTH - usecs.elapsed()));
usecs.reset();
}
// No need to turn off the LED as we will always end with a space().
@@ -647,7 +647,7 @@ void ICACHE_FLASH_ATTR IRsend::sendSherwood(unsigned long data, int nbits,
unsigned int repeat) {
// Sherwood remote codes appear to be NEC codes with a manditory repeat code.
// i.e. repeat should be >= 1.
sendNEC(data, nbits, max(1u, repeat));
sendNEC(data, nbits, max(1, repeat));
}
void ICACHE_FLASH_ATTR IRsend::sendMitsubishiAC(unsigned char data[]) {
@@ -911,7 +911,7 @@ bool ICACHE_FLASH_ATTR IRrecv::decode(decode_results *results,
// Nr. of ticks.
uint32_t IRrecv::ticksLow(uint32_t usecs, uint8_t tolerance) {
// max() used to ensure the result can't drop below 0 before the cast.
return((uint32_t) max(usecs * (1.0 - tolerance/100.)/USECPERTICK, 0.0));
return((uint32_t) max(usecs * (1.0 - tolerance/100.)/USECPERTICK, 0));
}
// Calculate the upper bound of the nr. of ticks.
+11 -21
View File
@@ -1,4 +1,11 @@
// Based on the work by DFRobot
//www.DFRobot.com
//last updated on 21/12/2011
//Tim Starling Fix the reset bug (Thanks Tim)
//wiki doc http://www.dfrobot.com/wiki/index.php?title=I2C/TWI_LCD1602_Module_(SKU:_DFR0063)
//Support Forum: http://www.dfrobot.com/forum/
//Compatible with the Arduino IDE 1.0
//Library version:1.1
#include "LiquidCrystal_I2C.h"
#include <inttypes.h>
@@ -9,7 +16,7 @@
#define printIIC(args) Wire.write(args)
inline size_t LiquidCrystal_I2C::write(uint8_t value) {
send(value, Rs);
return 1;
return 0;
}
#else
@@ -52,11 +59,6 @@ LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t lcd_Addr,uint8_t lcd_cols,uint8_t l
_backlightval = LCD_NOBACKLIGHT;
}
void LiquidCrystal_I2C::oled_init(){
_oled = true;
init_priv();
}
void LiquidCrystal_I2C::init(){
init_priv();
}
@@ -132,7 +134,6 @@ void LiquidCrystal_I2C::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
void LiquidCrystal_I2C::clear(){
command(LCD_CLEARDISPLAY);// clear display, set cursor position to zero
delayMicroseconds(2000); // this command takes a long time!
if (_oled) setCursor(0,0);
}
void LiquidCrystal_I2C::home(){
@@ -220,15 +221,6 @@ void LiquidCrystal_I2C::createChar(uint8_t location, uint8_t charmap[]) {
}
}
//createChar with PROGMEM input
void LiquidCrystal_I2C::createChar(uint8_t location, const char *charmap) {
location &= 0x7; // we only have 8 locations 0-7
command(LCD_SETCGRAMADDR | (location << 3));
for (int i=0; i<8; i++) {
write(pgm_read_byte_near(charmap++));
}
}
// Turn the (optional) backlight off/on
void LiquidCrystal_I2C::noBacklight(void) {
_backlightval=LCD_NOBACKLIGHT;
@@ -317,8 +309,6 @@ void LiquidCrystal_I2C::printstr(const char c[]){
// unsupported API functions
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
void LiquidCrystal_I2C::off(){}
void LiquidCrystal_I2C::on(){}
void LiquidCrystal_I2C::setDelay (int cmdDelay,int charDelay) {}
@@ -328,5 +318,5 @@ uint8_t LiquidCrystal_I2C::init_bargraph(uint8_t graphtype){return 0;}
void LiquidCrystal_I2C::draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_col_end){}
void LiquidCrystal_I2C::draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_row_end){}
void LiquidCrystal_I2C::setContrast(uint8_t new_val){}
#pragma GCC diagnostic pop
+2 -7
View File
@@ -1,4 +1,4 @@
//YWROBOT
//DFRobot.com
#ifndef LiquidCrystal_I2C_h
#define LiquidCrystal_I2C_h
@@ -77,18 +77,14 @@ public:
void autoscroll();
void noAutoscroll();
void createChar(uint8_t, uint8_t[]);
void createChar(uint8_t location, const char *charmap);
// Example: const char bell[8] PROGMEM = {B00100,B01110,B01110,B01110,B11111,B00000,B00100,B00000};
void setCursor(uint8_t, uint8_t);
#if defined(ARDUINO) && ARDUINO >= 100
#if defined(ARDUINO) && ARDUINO >= 100
virtual size_t write(uint8_t);
#else
virtual void write(uint8_t);
#endif
void command(uint8_t);
void init();
void oled_init();
////compatibility API function aliases
void blink_on(); // alias for blink()
@@ -122,7 +118,6 @@ private:
uint8_t _displaycontrol;
uint8_t _displaymode;
uint8_t _numlines;
bool _oled = false;
uint8_t _cols;
uint8_t _rows;
uint8_t _backlightval;
-2
View File
@@ -1,2 +0,0 @@
# LiquidCrystal_I2C
LiquidCrystal Arduino library for the DFRobot I2C LCD displays
+69
View File
@@ -0,0 +1,69 @@
1,6c1
< //www.DFRobot.com
< //last updated on 26/11/2010
< //Tim Starling Fix the reset bug (Thanks Tim)
< //wiki doc http://www.dfrobot.com/wiki/index.php?title=I2C/TWI_LCD1602_Module_(SKU:_DFR0063)
< //Support Forum: http://www.dfrobot.com/forum/
<
---
> // LiquidCrystal_I2C V2.0
10d4
< #include "WProgram.h"
12c6
<
---
> #include "Arduino.h"
67c61
< delay(50);
---
> delayMicroseconds(50000);
77,90c71,84
< // we start in 8bit mode, try to set 4 bit mode
< write4bits(0x03 << 4);
< delayMicroseconds(4500); // wait min 4.1ms
<
< // second try
< write4bits(0x03 << 4);
< delayMicroseconds(4500); // wait min 4.1ms
<
< // third go!
< write4bits(0x03 << 4);
< delayMicroseconds(150);
<
< // finally, set to 4-bit interface
< write4bits(0x02 << 4);
---
> // we start in 8bit mode, try to set 4 bit mode
> write4bits(0x03);
> delayMicroseconds(4500); // wait min 4.1ms
>
> // second try
> write4bits(0x03);
> delayMicroseconds(4500); // wait min 4.1ms
>
> // third go!
> write4bits(0x03);
> delayMicroseconds(150);
>
> // finally, set to 4-bit interface
> write4bits(0x02);
225c219
< inline void LiquidCrystal_I2C::write(uint8_t value) {
---
> inline size_t LiquidCrystal_I2C::write(uint8_t value) {
226a221
> return 0;
235,238c230,233
< uint8_t highnib=value&0xf0;
< uint8_t lownib=(value<<4)&0xf0;
< write4bits((highnib)|mode);
< write4bits((lownib)|mode);
---
> uint8_t highnib=value>>4;
> uint8_t lownib=value & 0x0F;
> write4bits((highnib)|mode);
> write4bits((lownib)|mode);
248c243
< Wire.send((int)(_data) | _backlightval);
---
> Wire.write((int)(_data) | _backlightval);
+4 -4
View File
@@ -1,4 +1,4 @@
//YWROBOT
//DFRobot.com
//Compatible with the Arduino IDE 1.0
//Library version:1.1
#include <Wire.h>
@@ -19,7 +19,7 @@ uint8_t check[8] = {0x0,0x1,0x3,0x16,0x1c,0x8,0x0};
uint8_t cross[8] = {0x0,0x1b,0xe,0x4,0xe,0x1b,0x0};
uint8_t retarrow[8] = { 0x1,0x1,0x5,0x9,0x1f,0x8,0x4};
LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
void setup()
{
@@ -52,7 +52,7 @@ void displayKeyCodes(void) {
while (1) {
lcd.clear();
lcd.print("Codes 0x"); lcd.print(i, HEX);
lcd.print("-0x"); lcd.print(i+15, HEX);
lcd.print("-0x"); lcd.print(i+16, HEX);
lcd.setCursor(0, 1);
for (int j=0; j<16; j++) {
lcd.printByte(i+j);
@@ -67,4 +67,4 @@ void loop()
{
}
+3 -11
View File
@@ -1,28 +1,20 @@
//YWROBOT
//DFRobot.com
//Compatible with the Arduino IDE 1.0
//Library version:1.1
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
void setup()
{
lcd.init(); // initialize the lcd
lcd.init();
// Print a message to the LCD.
lcd.backlight();
lcd.setCursor(3,0);
lcd.print("Hello, world!");
lcd.setCursor(2,1);
lcd.print("Ywrobot Arduino!");
lcd.setCursor(0,2);
lcd.print("Arduino LCM IIC 2004");
lcd.setCursor(2,3);
lcd.print("Power By Ec-yuan!");
}
void loop()
{
}
+2 -2
View File
@@ -1,14 +1,14 @@
/*
* Displays text sent over the serial port (e.g. from the Serial Monitor) on
* an attached LCD.
* YWROBOT
* DFRobot.com
*Compatible with the Arduino IDE 1.0
*Library version:1.1
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
void setup()
{
View File
-16
View File
@@ -1,16 +0,0 @@
{
"name": "LiquidCrystal_I2C",
"keywords": "LCD, liquidcrystal, I2C",
"description": "A library for DFRobot I2C LCD displays",
"repository":
{
"type": "git",
"url": "https://github.com/marcoschwartz/LiquidCrystal_I2C.git"
},
"frameworks": "arduino",
"platforms":
[
"atmelavr",
"espressif8266"
]
}
-9
View File
@@ -1,9 +0,0 @@
name=LiquidCrystal_I2C
version=1.1.4
author=Frank de Brabander
maintainer=Marco Schwartz <marcolivier.schwartz@gmail.com>
sentence=A library for I2C LCD displays.
paragraph= The library allows to control I2C displays with functions extremely similar to LiquidCrystal library. THIS LIBRARY MIGHT NOT BE COMPATIBLE WITH EXISTING SKETCHES.
category=Display
url=https://github.com/marcoschwartz/LiquidCrystal_I2C
architectures=avr
+116 -29
View File
@@ -25,7 +25,7 @@
#include "jkSDS011.h"
CjkSDS011::CjkSDS011(int16_t pinRX, int16_t pinTX) : _serial(pinRX, pinTX)
CjkSDS011::CjkSDS011(int16_t pinRX, int16_t pinTX)
{
_sws = ! ( pinRX < 0 || pinRX == 3 );
_pm2_5 = NAN;
@@ -35,43 +35,131 @@ CjkSDS011::CjkSDS011(int16_t pinRX, int16_t pinTX) : _serial(pinRX, pinTX)
_pm10_avr = 0;
_avr = 0;
_data.SetPacketLength(10);
_command.SetPacketLength(19);
_working_period = -1;
_sleepmode_active = false;
_serial = new ESPeasySoftwareSerial(pinRX, pinTX);
_serial->begin(9600);
}
_serial.begin(9600);
CjkSDS011::~CjkSDS011() {
delete _serial;
}
void CjkSDS011::SendCommand(byte byte1, byte byte2, byte byte3) {
_command[0] = 0xAA; // Head
_command[1] = 0xB4; // Command ID
_command[2] = byte1; // Data Byte 1
_command[3] = byte2; // Data Byte 2
_command[4] = byte3; // Data Byte 3
_command[5] = 0; // Data Byte 4
_command[6] = 0; // Data Byte 5
_command[7] = 0; // Data Byte 6
_command[8] = 0; // Data Byte 7
_command[9] = 0; // Data Byte 8
_command[10] = 0; // Data Byte 9
_command[11] = 0; // Data Byte 10
_command[12] = 0; // Data Byte 11
_command[13] = 0; // Data Byte 12
_command[14] = 0; // Data Byte 13
_command[15] = 0xFF; // Device ID byte 1, FF: All sensor response
_command[16] = 0xFF; // Device ID byte 2, FF: All sensor response
byte checksum = 0;
for (byte i=2; i< 17; ++i) {
checksum += _command[i];
}
_command[17] = checksum; // Checksum
_command[18] = 0xAB; // Tail
for (int i = 0; i < 19; ++i) {
_serial->write(_command[i]);
}
}
void CjkSDS011::SetSleepMode(bool enabled) {
byte databyte3 = enabled ? 0 : 1;
SendCommand(6, 1, databyte3);
}
void CjkSDS011::SetWorkingPeriod(int minutes) {
// Data byte 1: 8
// Data byte 2: 0: query the current mode
// 1: set mode
// Data byte 3: 0continuous(default)
// 1-30minutework 30 seconds and sleep n*60-30 seconds
if (minutes < 0 || minutes > 30) return;
// Working period is stored in the flash of the sensor. Only write to change.
const int currentWorkingPeriod = GetWorkingPeriod();
if (minutes != currentWorkingPeriod)
SendCommand(8, 1, minutes);
}
int CjkSDS011::GetWorkingPeriod() {
// Data byte 1: 8
// Data byte 2: 0: query the current mode
// 1: set mode
// Data byte 3: 0continuous(default)
// 1-30minutework 30 seconds and sleep n*60-30 seconds
SendCommand(8, 0, 0);
Process();
return _working_period;
}
void CjkSDS011::ParseCommandReply() {
switch(_data[2]) {
case 6: // Enable/Disable sleep mode.
if (_data[3] == 0)
_sleepmode_active = _data[4];
break;
case 8: // Set/Get working period
if (_data[3] == 0)
_working_period = _data[4];
break;
default:
// Not implemented.
break;
}
}
void CjkSDS011::Process()
{
while (_serial.available())
while (_serial->available())
{
_data.AddData(_serial.read());
_data.AddData(_serial->read());
if (_data[0] == 0xAA && _data[9] == 0xAB && (_data[1] == 0xC0 || _data[1] == 0xCF)) // correct packet frame?
if (_data[0] == 0xAA && _data[9] == 0xAB) // correct packet frame?
{
byte checksum = 0;
for (byte i=2; i<= 7; i++)
checksum += _data[i];
checksum += _data[i];
if (checksum != _data[8])
continue;
if (_data[1] == 0xC0) // SDS011 or SDS018?
{
_pm2_5 = (float)((_data[3] << 8) | _data[2]) * 0.1;
_pm10_ = (float)((_data[5] << 8) | _data[4]) * 0.1;
_available = true;
switch(_data[1]) {
case 0xC0: // SDS011 or SDS018?
_pm2_5 = (float)((_data[3] << 8) | _data[2]) * 0.1;
_pm10_ = (float)((_data[5] << 8) | _data[4]) * 0.1;
_available = true;
break;
case 0xCF: // SDS198?
_pm2_5 = (float)((_data[5] << 8) | _data[4]);
_pm10_ = (float)((_data[3] << 8) | _data[2]);
_available = true;
break;
case 0xC5: // Reply on command ID 0xB4
ParseCommandReply();
break;
default:
break;
}
else if (_data[1] == 0xCF) // SDS198?
{
_pm2_5 = (float)((_data[5] << 8) | _data[4]);
_pm10_ = (float)((_data[3] << 8) | _data[2]);
_available = true;
if (_available) {
_pm2_5avr += _pm2_5;
_pm10_avr += _pm10_;
_avr++;
_data.Clear();
return;
}
else
continue;
_pm2_5avr += _pm2_5;
_pm10_avr += _pm10_;
_avr++;
return;
}
}
}
@@ -83,7 +171,7 @@ boolean CjkSDS011::available()
return ret;
}
void CjkSDS011::ReadAverage(float &pm25, float &pm10)
boolean CjkSDS011::ReadAverage(float &pm25, float &pm10)
{
if (_avr)
{
@@ -92,10 +180,9 @@ void CjkSDS011::ReadAverage(float &pm25, float &pm10)
_pm2_5avr = 0;
_pm10_avr = 0;
_avr = 0;
return true;
}
else
{
pm25 = NAN;
pm10 = NAN;
}
pm25 = NAN;
pm10 = NAN;
return false;
}
+24 -3
View File
@@ -27,13 +27,15 @@
#define _jkSDS011_H_
#include "Arduino.h"
#include "SensorSerial.h"
//#include "SensorSerial.h"
#include "SensorSerialBuffer.h"
#include "ESPeasySoftwareSerial.h"
class CjkSDS011
{
public:
CjkSDS011(int16_t pinRX, int16_t pinTX);
virtual ~CjkSDS011();
void Process();
@@ -42,11 +44,28 @@ public:
float GetPM2_5() { return _pm2_5; };
float GetPM10_() { return _pm10_; };
void ReadAverage(float &pm25, float &pm10);
// Return true when there are valid samples.
boolean ReadAverage(float &pm25, float &pm10);
void SetSleepMode(bool enabled);
// Set interval to get new data, 0 .. 30 minutes.
// Minutes = 0 => continous mode.
// The setting is still effective after power off(factory default is continuous measurement)
void SetWorkingPeriod(int minutes);
// Get the working period in minutes (0 = continuous reading)
// Negative return value indicates error during communication.
int GetWorkingPeriod();
private:
SensorSerial _serial;
void SendCommand(byte byte1, byte byte2, byte byte3);
void ParseCommandReply();
// SensorSerial _serial;
ESPeasySoftwareSerial *_serial;
CSensorSerialBuffer _data;
CSensorSerialBuffer _command;
float _pm2_5;
float _pm10_;
float _pm2_5avr;
@@ -54,6 +73,8 @@ private:
uint16_t _avr;
boolean _available;
boolean _sws;
int _working_period;
boolean _sleepmode_active;
};
#endif
+34 -55
View File
@@ -27,32 +27,24 @@
#include "OLEDDisplay.h"
OLEDDisplay::~OLEDDisplay() {
end();
}
bool OLEDDisplay::init() {
if (!this->connect()) {
DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Can't establish connection to display\n");
return false;
}
if(this->buffer==NULL) {
this->buffer = (uint8_t*) malloc(sizeof(uint8_t) * DISPLAY_BUFFER_SIZE);
if(!this->buffer) {
DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Not enough memory to create display\n");
return false;
}
}
#ifdef OLEDDISPLAY_DOUBLE_BUFFER
if(this->buffer_back==NULL) {
this->buffer_back = (uint8_t*) malloc(sizeof(uint8_t) * DISPLAY_BUFFER_SIZE);
if(!this->buffer_back) {
DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Not enough memory to create back buffer\n");
free(this->buffer);
return false;
}
}
#endif
sendInitCommands();
@@ -62,11 +54,10 @@ bool OLEDDisplay::init() {
}
void OLEDDisplay::end() {
if (this->buffer) { free(this->buffer); this->buffer = NULL; }
if (this->buffer) free(this->buffer);
#ifdef OLEDDISPLAY_DOUBLE_BUFFER
if (this->buffer_back) { free(this->buffer_back); this->buffer_back = NULL; }
if (this->buffer_back) free(this->buffer_back);
#endif
if (this->logBuffer != NULL) { free(this->logBuffer); this->logBuffer = NULL; }
}
void OLEDDisplay::resetDisplay(void) {
@@ -82,11 +73,11 @@ void OLEDDisplay::setColor(OLEDDISPLAY_COLOR color) {
}
void OLEDDisplay::setPixel(int16_t x, int16_t y) {
if (x >= 0 && x < this->width() && y >= 0 && y < this->height()) {
if (x >= 0 && x < 128 && y >= 0 && y < 64) {
switch (color) {
case WHITE: buffer[x + (y / 8) * this->width()] |= (1 << (y & 7)); break;
case BLACK: buffer[x + (y / 8) * this->width()] &= ~(1 << (y & 7)); break;
case INVERSE: buffer[x + (y / 8) * this->width()] ^= (1 << (y & 7)); break;
case WHITE: buffer[x + (y / 8) * DISPLAY_WIDTH] |= (1 << (y & 7)); break;
case BLACK: buffer[x + (y / 8) * DISPLAY_WIDTH] &= ~(1 << (y & 7)); break;
case INVERSE: buffer[x + (y / 8) * DISPLAY_WIDTH] ^= (1 << (y & 7)); break;
}
}
}
@@ -231,21 +222,21 @@ void OLEDDisplay::fillCircle(int16_t x0, int16_t y0, int16_t radius) {
}
void OLEDDisplay::drawHorizontalLine(int16_t x, int16_t y, int16_t length) {
if (y < 0 || y >= this->height()) { return; }
if (y < 0 || y >= DISPLAY_HEIGHT) { return; }
if (x < 0) {
length += x;
x = 0;
}
if ( (x + length) > this->width()) {
length = (this->width() - x);
if ( (x + length) > DISPLAY_WIDTH) {
length = (DISPLAY_WIDTH - x);
}
if (length <= 0) { return; }
uint8_t * bufferPtr = buffer;
bufferPtr += (y >> 3) * this->width();
bufferPtr += (y >> 3) * DISPLAY_WIDTH;
bufferPtr += x;
uint8_t drawBit = 1 << (y & 7);
@@ -264,15 +255,15 @@ void OLEDDisplay::drawHorizontalLine(int16_t x, int16_t y, int16_t length) {
}
void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) {
if (x < 0 || x >= this->width()) return;
if (x < 0 || x >= DISPLAY_WIDTH) return;
if (y < 0) {
length += y;
y = 0;
}
if ( (y + length) > this->height()) {
length = (this->height() - y);
if ( (y + length) > DISPLAY_HEIGHT) {
length = (DISPLAY_HEIGHT - y);
}
if (length <= 0) return;
@@ -282,7 +273,7 @@ void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) {
uint8_t drawBit;
uint8_t *bufferPtr = buffer;
bufferPtr += (y >> 3) * this->width();
bufferPtr += (y >> 3) * DISPLAY_WIDTH;
bufferPtr += x;
if (yOffset) {
@@ -302,7 +293,7 @@ void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) {
if (length < yOffset) return;
length -= yOffset;
bufferPtr += this->width();
bufferPtr += DISPLAY_WIDTH;
}
if (length >= 8) {
@@ -312,14 +303,14 @@ void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) {
drawBit = (color == WHITE) ? 0xFF : 0x00;
do {
*bufferPtr = drawBit;
bufferPtr += this->width();
bufferPtr += DISPLAY_WIDTH;
length -= 8;
} while (length >= 8);
break;
case INVERSE:
do {
*bufferPtr = ~(*bufferPtr);
bufferPtr += this->width();
bufferPtr += DISPLAY_WIDTH;
length -= 8;
} while (length >= 8);
break;
@@ -349,7 +340,7 @@ void OLEDDisplay::drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16
drawHorizontalLine(xRadius, y + height, width - doubleRadius + 1);
drawCircleQuads(x + width - radius, yRadius, radius, 0b00001001);
uint16_t maxProgressWidth = (width - doubleRadius + 1) * progress / 100;
uint16_t maxProgressWidth = (width - doubleRadius - 1) * progress / 100;
fillCircle(xRadius, yRadius, innerRadius);
fillRect(xRadius + 1, y + 2, maxProgressWidth, height - 3);
@@ -362,7 +353,7 @@ void OLEDDisplay::drawFastImage(int16_t xMove, int16_t yMove, int16_t width, int
void OLEDDisplay::drawXbm(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const char *xbm) {
int16_t widthInXbm = (width + 7) / 8;
uint8_t data = 0;
uint8_t data;
for(int16_t y = 0; y < height; y++) {
for(int16_t x = 0; x < width; x++ ) {
@@ -397,13 +388,11 @@ void OLEDDisplay::drawStringInternal(int16_t xMove, int16_t yMove, char* text, u
case TEXT_ALIGN_RIGHT:
xMove -= textWidth;
break;
case TEXT_ALIGN_LEFT:
break;
}
// Don't draw anything if it is not on the screen.
if (xMove + textWidth < 0 || xMove > this->width() ) {return;}
if (yMove + textHeight < 0 || yMove > this->width() ) {return;}
if (xMove + textWidth < 0 || xMove > DISPLAY_WIDTH ) {return;}
if (yMove + textHeight < 0 || yMove > DISPLAY_HEIGHT) {return;}
for (uint16_t j = 0; j < textLength; j++) {
int16_t xPos = xMove + cursorX;
@@ -556,16 +545,9 @@ void OLEDDisplay::normalDisplay(void) {
sendCommand(NORMALDISPLAY);
}
void OLEDDisplay::setContrast(char contrast, char precharge, char comdetect) {
sendCommand(SETPRECHARGE); //0xD9
sendCommand(precharge); //0xF1 default, to lower the contrast, put 1-1F
void OLEDDisplay::setContrast(char contrast) {
sendCommand(SETCONTRAST);
sendCommand(contrast); // 0-255
sendCommand(SETVCOMDETECT); //0xDB, (additionally needed to lower the contrast)
sendCommand(comdetect); //0x40 default, to lower the contrast, put 0
sendCommand(DISPLAYALLON_RESUME);
sendCommand(NORMALDISPLAY);
sendCommand(DISPLAYON);
sendCommand(contrast);
}
void OLEDDisplay::flipScreenVertically() {
@@ -614,7 +596,6 @@ bool OLEDDisplay::setLogBuffer(uint16_t lines, uint16_t chars){
uint16_t size = lines * chars;
if (size > 0) {
this->logBufferLine = 0; // Lines printed
this->logBufferFilled = 0; // Nothing stored yet
this->logBufferMaxLines = lines; // Lines max printable
this->logBufferSize = size; // Total number of characters the buffer can hold
this->logBuffer = (char *) malloc(size * sizeof(uint8_t));
@@ -689,7 +670,7 @@ void OLEDDisplay::sendInitCommands(void) {
sendCommand(SETDISPLAYCLOCKDIV);
sendCommand(0xF0); // Increase speed of the display max ~96Hz
sendCommand(SETMULTIPLEX);
sendCommand(this->height() - 1);
sendCommand(0x3F);
sendCommand(SETDISPLAYOFFSET);
sendCommand(0x00);
sendCommand(SETSTARTLINE);
@@ -700,13 +681,11 @@ void OLEDDisplay::sendInitCommands(void) {
sendCommand(SEGREMAP);
sendCommand(COMSCANINC);
sendCommand(SETCOMPINS);
sendCommand(0x12); // according to the adafruit lib, sometimes this may need to be 0x02
sendCommand(0x12);
sendCommand(SETCONTRAST);
sendCommand(0xCF);
sendCommand(SETPRECHARGE);
sendCommand(0xF1);
sendCommand(SETVCOMDETECT); //0xDB, (additionally needed to lower the contrast)
sendCommand(0x40); //0x40 default, to lower the contrast, put 0
sendCommand(DISPLAYALLON_RESUME);
sendCommand(NORMALDISPLAY);
sendCommand(0x2e); // stop scroll
@@ -715,8 +694,8 @@ void OLEDDisplay::sendInitCommands(void) {
void inline OLEDDisplay::drawInternal(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const char *data, uint16_t offset, uint16_t bytesInData) {
if (width < 0 || height < 0) return;
if (yMove + height < 0 || yMove > this->height()) return;
if (xMove + width < 0 || xMove > this->width()) return;
if (yMove + height < 0 || yMove > DISPLAY_HEIGHT) return;
if (xMove + width < 0 || xMove > DISPLAY_WIDTH) return;
uint8_t rasterHeight = 1 + ((height - 1) >> 3); // fast ceil(height / 8.0)
int8_t yOffset = yMove & 7;
@@ -738,13 +717,13 @@ void inline OLEDDisplay::drawInternal(int16_t xMove, int16_t yMove, int16_t widt
byte currentByte = pgm_read_byte(data + offset + i);
int16_t xPos = xMove + (i / rasterHeight);
int16_t yPos = ((yMove >> 3) + (i % rasterHeight)) * this->width();
int16_t yPos = ((yMove >> 3) + (i % rasterHeight)) * DISPLAY_WIDTH;
// int16_t yScreenPos = yMove + yOffset;
int16_t yScreenPos = yMove + yOffset;
int16_t dataPos = xPos + yPos;
if (dataPos >= 0 && dataPos < DISPLAY_BUFFER_SIZE &&
xPos >= 0 && xPos < this->width() ) {
xPos >= 0 && xPos < DISPLAY_WIDTH ) {
if (yOffset >= 0) {
switch (this->color) {
@@ -752,11 +731,11 @@ void inline OLEDDisplay::drawInternal(int16_t xMove, int16_t yMove, int16_t widt
case BLACK: buffer[dataPos] &= ~(currentByte << yOffset); break;
case INVERSE: buffer[dataPos] ^= currentByte << yOffset; break;
}
if (dataPos < (DISPLAY_BUFFER_SIZE - this->width())) {
if (dataPos < (DISPLAY_BUFFER_SIZE - DISPLAY_WIDTH)) {
switch (this->color) {
case WHITE: buffer[dataPos + this->width()] |= currentByte >> (8 - yOffset); break;
case BLACK: buffer[dataPos + this->width()] &= ~(currentByte >> (8 - yOffset)); break;
case INVERSE: buffer[dataPos + this->width()] ^= currentByte >> (8 - yOffset); break;
case WHITE: buffer[dataPos + DISPLAY_WIDTH] |= currentByte >> (8 - yOffset); break;
case BLACK: buffer[dataPos + DISPLAY_WIDTH] &= ~(currentByte >> (8 - yOffset)); break;
case INVERSE: buffer[dataPos + DISPLAY_WIDTH] ^= currentByte >> (8 - yOffset); break;
}
}
} else {
+9 -21
View File
@@ -44,13 +44,9 @@
// Display settings
#ifndef DISPLAY_WIDTH
#define DISPLAY_WIDTH 128
#endif
#ifndef DISPLAY_HEIGHT
#define DISPLAY_HEIGHT 64
#endif
#define DISPLAY_BUFFER_SIZE DISPLAY_WIDTH * DISPLAY_HEIGHT / 8
#define DISPLAY_WIDTH 128
#define DISPLAY_HEIGHT 64
#define DISPLAY_BUFFER_SIZE 1024
// Header Values
#define JUMPTABLE_BYTES 4
@@ -113,17 +109,11 @@ enum OLEDDISPLAY_TEXT_ALIGNMENT {
class OLEDDisplay : public Print {
private:
const int _width, _height;
public:
OLEDDisplay(const int width = DISPLAY_WIDTH, const int height = DISPLAY_HEIGHT) : _width(width), _height(height){ };
virtual ~OLEDDisplay();
const int width(void) const { return _width; };
const int height(void) const { return _height; };
virtual ~OLEDDisplay() {}
// Initialize the display
// Initialize the display
bool init();
// Free the memory used by the display
@@ -214,9 +204,7 @@ class OLEDDisplay : public Print {
void normalDisplay(void);
// Set display contrast
// really low brightness & contrast: contrast = 10, precharge = 5, comdetect = 0
// normal brightness & contrast: contrast = 100
void setContrast(char contrast, char precharge = 241, char comdetect = 64);
void setContrast(char contrast);
// Turn the display upside down
void flipScreenVertically();
@@ -241,10 +229,10 @@ class OLEDDisplay : public Print {
size_t write(uint8_t c);
size_t write(const char* s);
uint8_t *buffer = NULL;
uint8_t *buffer;
#ifdef OLEDDISPLAY_DOUBLE_BUFFER
uint8_t *buffer_back = NULL;
uint8_t *buffer_back;
#endif
protected:
@@ -262,7 +250,7 @@ class OLEDDisplay : public Print {
char *logBuffer = NULL;
// Send a command to the display (low level function)
virtual void sendCommand(uint8_t com) {(void)com;};
virtual void sendCommand(uint8_t com) {};
// Connect to the display
virtual bool connect() { return false; };
+17 -17
View File
@@ -251,31 +251,31 @@ void OLEDDisplayUi::drawFrame(){
switch (this->state.frameState){
case IN_TRANSITION: {
float progress = (float) this->state.ticksSinceLastStateSwitch / (float) this->ticksPerTransition;
int16_t x = 0, y = 0, x1 = 0, y1 = 0;
int16_t x, y, x1, y1;
switch(this->frameAnimationDirection){
case SLIDE_LEFT:
x = -this->display->width() * progress;
x = -128 * progress;
y = 0;
x1 = x + this->display->width();
x1 = x + 128;
y1 = 0;
break;
case SLIDE_RIGHT:
x = this->display->width() * progress;
x = 128 * progress;
y = 0;
x1 = x - this->display->width();
x1 = x - 128;
y1 = 0;
break;
case SLIDE_UP:
x = 0;
y = -this->display->height() * progress;
y = -64 * progress;
x1 = 0;
y1 = y + this->display->height();
y1 = y + 64;
break;
case SLIDE_DOWN:
x = 0;
y = this->display->height() * progress;
y = 64 * progress;
x1 = 0;
y1 = y - this->display->height();
y1 = y - 64;
break;
}
@@ -331,7 +331,7 @@ void OLEDDisplayUi::drawIndicator() {
return;
}
uint8_t posOfHighlightFrame = 0;
uint8_t posOfHighlightFrame;
float indicatorFadeProgress = 0;
// if the indicator needs to be slided in we want to
@@ -362,25 +362,25 @@ void OLEDDisplayUi::drawIndicator() {
uint16_t frameStartPos = (12 * frameCount / 2);
const char *image;
uint16_t x = 0, y = 0;
uint16_t x,y;
for (byte i = 0; i < this->frameCount; i++) {
switch (this->indicatorPosition){
case TOP:
y = 0 - (8 * indicatorFadeProgress);
x = (this->display->width() / 2) - frameStartPos + 12 * i;
x = 64 - frameStartPos + 12 * i;
break;
case BOTTOM:
y = (this->display->height() - 8) + (8 * indicatorFadeProgress);
x = (this->display->width() / 2) - frameStartPos + 12 * i;
y = 56 + (8 * indicatorFadeProgress);
x = 64 - frameStartPos + 12 * i;
break;
case RIGHT:
x = (this->display->width() - 8) + (8 * indicatorFadeProgress);
y = (this->display->height() / 2) - frameStartPos + 2 + 12 * i;
x = 120 + (8 * indicatorFadeProgress);
y = 32 - frameStartPos + 2 + 12 * i;
break;
case LEFT:
x = 0 - (8 * indicatorFadeProgress);
y = (this->display->height() / 2) - frameStartPos + 2 + 12 * i;
y = 32 - frameStartPos + 2 + 12 * i;
break;
}
@@ -1,45 +0,0 @@
#ifndef OLED_SSD1306_SH1106_IMAGES_H
#define OLED_SSD1306_SH1106_IMAGES_H
#define espeasy_logo_width 36
#define espeasy_logo_height 36
const char espeasy_logo_bits[] PROGMEM= {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x60, 0x40, 0xc0, 0x00, 0x00, 0x70, 0xf0, 0xe0,
0x01, 0x00, 0x78, 0xf8, 0xf0, 0x01, 0x00, 0x3c, 0x7c, 0xf8, 0x00, 0x00,
0x1e, 0x3e, 0x7c, 0x00, 0x00, 0x0f, 0x1f, 0x3e, 0x00, 0x80, 0x87, 0x0f,
0x1f, 0x00, 0xc0, 0xc3, 0x87, 0x0f, 0x00, 0xe0, 0xe1, 0xc3, 0x07, 0x00,
0xf0, 0xf0, 0xe1, 0xc3, 0x00, 0x78, 0xf8, 0xf0, 0xe1, 0x01, 0x30, 0x7c,
0xf8, 0xf0, 0x00, 0x00, 0x3e, 0x7c, 0x78, 0x00, 0x00, 0x1f, 0x3e, 0x3c,
0x00, 0x80, 0x0f, 0x1f, 0x1e, 0x00, 0xc0, 0x87, 0x0f, 0x0f, 0x00, 0xe0,
0xc3, 0x87, 0x07, 0x00, 0xf0, 0xe1, 0xc3, 0x03, 0x00, 0xf0, 0xf0, 0xe1,
0x01, 0x00, 0x78, 0xf8, 0xf0, 0x00, 0x00, 0x30, 0x7c, 0x78, 0x00, 0x00,
0x00, 0x3e, 0x3c, 0x00, 0x00, 0x00, 0x1f, 0x1e, 0x00, 0x00, 0x80, 0x0f,
0x0f, 0x78, 0x00, 0xc0, 0x87, 0x07, 0xfc, 0x00, 0xe0, 0xc3, 0x03, 0xfc,
0x01, 0xf0, 0xe1, 0x01, 0xfc, 0x01, 0xf8, 0xf0, 0x00, 0xfc, 0x00, 0x78,
0x70, 0x00, 0x78, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
const char activeSymbole[] PROGMEM = {
B00000000,
B00000000,
B00011000,
B00100100,
B01000010,
B01000010,
B00100100,
B00011000
};
const char inactiveSymbole[] PROGMEM = {
B00000000,
B00000000,
B00000000,
B00000000,
B00011000,
B00011000,
B00000000,
B00000000
};
#endif
+11 -13
View File
@@ -38,8 +38,7 @@ class SSD1306Wire : public OLEDDisplay {
uint8_t _scl;
public:
SSD1306Wire(uint8_t _address, uint8_t _sda, uint8_t _scl, int width = DISPLAY_WIDTH, int height = DISPLAY_HEIGHT)
: OLEDDisplay(width, height) {
SSD1306Wire(uint8_t _address, uint8_t _sda, uint8_t _scl) {
this->_address = _address;
this->_sda = _sda;
this->_scl = _scl;
@@ -54,7 +53,6 @@ class SSD1306Wire : public OLEDDisplay {
}
void display(void) {
const int x_offset = (128 - this->width()) / 2;
#ifdef OLEDDISPLAY_DOUBLE_BUFFER
uint8_t minBoundY = ~0;
uint8_t maxBoundY = 0;
@@ -65,9 +63,9 @@ class SSD1306Wire : public OLEDDisplay {
// Calculate the Y bounding box of changes
// and copy buffer[pos] to buffer_back[pos];
for (y = 0; y < (this->height() / 8); y++) {
for (x = 0; x < this->width(); x++) {
uint16_t pos = x + y * this->width();
for (y = 0; y < (DISPLAY_HEIGHT / 8); y++) {
for (x = 0; x < DISPLAY_WIDTH; x++) {
uint16_t pos = x + y * DISPLAY_WIDTH;
if (buffer[pos] != buffer_back[pos]) {
minBoundY = _min(minBoundY, y);
maxBoundY = _max(maxBoundY, y);
@@ -82,11 +80,11 @@ class SSD1306Wire : public OLEDDisplay {
// If the minBoundY wasn't updated
// we can savely assume that buffer_back[pos] == buffer[pos]
// holdes true for all values of pos
if (minBoundY == (uint8_t)(~0)) return;
if (minBoundY == ~0) return;
sendCommand(COLUMNADDR);
sendCommand(x_offset + minBoundX);
sendCommand(x_offset + maxBoundX);
sendCommand(minBoundX);
sendCommand(maxBoundX);
sendCommand(PAGEADDR);
sendCommand(minBoundY);
@@ -99,7 +97,7 @@ class SSD1306Wire : public OLEDDisplay {
Wire.beginTransmission(_address);
Wire.write(0x40);
}
Wire.write(buffer[x + y * this->width()]);
Wire.write(buffer[x + y * DISPLAY_WIDTH]);
k++;
if (k == 16) {
Wire.endTransmission();
@@ -115,12 +113,12 @@ class SSD1306Wire : public OLEDDisplay {
#else
sendCommand(COLUMNADDR);
sendCommand(x_offset);
sendCommand(x_offset + (this->width() - 1));
sendCommand(0x0);
sendCommand(0x7F);
sendCommand(PAGEADDR);
sendCommand(0x0);
sendCommand((this->height() / 8) - 1);
sendCommand(0x7);
for (uint16_t i=0; i < DISPLAY_BUFFER_SIZE; i++) {
Wire.beginTransmission(this->_address);
+3 -3
View File
@@ -244,7 +244,7 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) {
buffer[len++] = digit;
length += (digit & 127) * multiplier;
multiplier *= 128;
} while ((digit & 128) != 0 && len < (MQTT_MAX_PACKET_SIZE -2));
} while ((digit & 128) != 0);
*lengthLength = len-1;
if (isPublish) {
@@ -420,7 +420,7 @@ boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsig
lastOutActivity = millis();
return rc == tlen + 3 + llen + plength;
return rc == tlen + 4 + plength;
}
boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) {
@@ -525,7 +525,7 @@ uint16_t PubSubClient::writeString(const char* string, uint8_t* buf, uint16_t po
const char* idp = string;
uint16_t i = 0;
pos += 2;
while (*idp && pos < (MQTT_MAX_PACKET_SIZE - 2)) {
while (*idp) {
buf[pos++] = *idp++;
i++;
}
+1 -1
View File
@@ -73,7 +73,7 @@
#define MQTTQOS1 (1 << 1)
#define MQTTQOS2 (2 << 1)
#if defined(ESP8266) || defined(ESP32)
#ifdef ESP8266
#include <functional>
#define MQTT_CALLBACK_SIGNATURE std::function<void(char*, uint8_t*, unsigned int)> callback
#else
-12
View File
@@ -1,12 +0,0 @@
#!/bin/bash
PATCH=puya.patch
for DIR in ~/.platformio/packages/framework-arduinoespressif8266*/; do
#not applied yet? (in upstream or otherwise)
if ! grep FLASH_QUIRK_WRITE_0_TO_1 $DIR/cores/esp8266/Esp.cpp >/dev/null; then
echo "Patching $DIR"
patch -p1 -d $DIR < $PATCH
fi
done
-32
View File
@@ -1,32 +0,0 @@
---
cores/esp8266/Esp.cpp | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/cores/esp8266/Esp.cpp b/cores/esp8266/Esp.cpp
index f4c0b220..c5c32f74 100644
--- a/cores/esp8266/Esp.cpp
+++ b/cores/esp8266/Esp.cpp
@@ -501,7 +501,21 @@ bool EspClass::flashEraseSector(uint32_t sector) {
bool EspClass::flashWrite(uint32_t offset, uint32_t *data, size_t size) {
ets_isr_mask(FLASH_INT_MASK);
- int rc = spi_flash_write(offset, (uint32_t*) data, size);
+ int rc;
+ uint32_t* ptr = data;
+#ifdef FLASH_QUIRK_WRITE_0_TO_1
+ static uint32_t read_buf[SPI_FLASH_SEC_SIZE / 4];
+ rc = spi_flash_read(offset, read_buf, size);
+ if (rc != 0) {
+ ets_isr_unmask(FLASH_INT_MASK);
+ return false;
+ }
+ for (size_t i = 0; i < size / 4; ++i) {
+ read_buf[i] &= data[i];
+ }
+ ptr = read_buf;
+#endif // FLASH_QUIRK_WRITE_0_TO_1
+ rc = spi_flash_write(offset, ptr, size);
ets_isr_unmask(FLASH_INT_MASK);
return rc == 0;
}
--
+10 -66
View File
@@ -7,7 +7,7 @@
#minimal version for esps with 512K or less flash (only has minimal plugin set)
; [env:mini_512]
; platform = espressif8266@1.5.0
; platform = espressif8266
; framework = arduino
; board = esp01
; upload_speed=460800
@@ -22,24 +22,11 @@
[common]
build_flags = -D BUILD_GIT='"${env.TRAVIS_TAG}"'
lib_deps = ""
#normal version with stable plugins, 1024k version
[env:normal_ESP8266_1024]
platform = espressif8266@1.5.0
lib_deps = ${common.lib_deps}
board_flash_mode = dout
framework = arduino
board = esp12e
upload_speed=460800
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld
# upload_port = /dev/ttyUSB0
[env:normal_ESP8266_1024_DOUT]
platform = espressif8266@1.5.0
lib_deps = ${common.lib_deps}
board_flash_mode = dout
platform = espressif8266
framework = arduino
board = esp12e
upload_speed=460800
@@ -48,8 +35,7 @@ build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld
#normal version with stable plugins, 4096k version
[env:normal_ESP8266_4096]
platform = espressif8266@1.5.0
lib_deps = ${common.lib_deps}
platform = espressif8266
framework = arduino
board = esp12e
upload_speed=460800
@@ -58,9 +44,7 @@ build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.4m1m.ld
#normal version with stable plugins, 4096k version for esp8285
[env:normal_ESP8285_1024]
platform = espressif8266@1.5.0
lib_deps = ${common.lib_deps}
board_flash_mode = dout
platform = espressif8266
framework = arduino
board = esp8285
upload_speed=460800
@@ -70,9 +54,7 @@ build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld -DESP8285
#version with additional plugins (and dependend code) that are in test-stadium 1024k
[env:test_ESP8266_1024]
platform = espressif8266@1.5.0
lib_deps = ${common.lib_deps}
board_flash_mode = dout
platform = espressif8266
framework = arduino
board = esp12e
upload_speed=460800
@@ -80,26 +62,15 @@ build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld -D PLUGIN_BUILD
#version with additional plugins (and dependend code) that are in test-stadium 4096k
[env:test_ESP8266_4096]
platform = espressif8266@1.5.0
lib_deps = ${common.lib_deps}
platform = espressif8266
framework = arduino
board = esp12e
upload_speed=460800
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.4m1m.ld -D PLUGIN_BUILD_TESTING
[env:test_ESP8266_4096_VCC]
platform = espressif8266@1.5.0
lib_deps = ${common.lib_deps}
framework = arduino
board = esp12e
upload_speed=460800
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.4m1m.ld -D PLUGIN_BUILD_TESTING -D FEATURE_ADC_VCC=true
#version with additional plugins (and dependend code) that are in test-stadium 4096k for esp8285
[env:test_ESP8285_1024]
platform = espressif8266@1.5.0
lib_deps = ${common.lib_deps}
board_flash_mode = dout
platform = espressif8266
framework = arduino
board = esp8285
upload_speed=460800
@@ -108,9 +79,7 @@ build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld -D PLUGIN_BUILD
#version with additional plugins (and dependend code) that is in development (probably broken or incomplete) 1024k
[env:dev_ESP8266_1024]
platform = espressif8266@1.5.0
lib_deps = ${common.lib_deps}
board_flash_mode = dout
platform = espressif8266
framework = arduino
board = esp12e
upload_speed=460800
@@ -118,8 +87,7 @@ build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld -D PLUGIN_BUILD
#version with additional plugins (and dependend code) that is in development (probably broken or incomplete) 4096k
[env:dev_ESP8266_4096]
platform = espressif8266@1.5.0
lib_deps = ${common.lib_deps}
platform = espressif8266
framework = arduino
board = esp12e
upload_speed=460800
@@ -127,32 +95,8 @@ build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.4m1m.ld -D PLUGIN_BUILD_
#version with additional plugins (and dependend code) that is in development (probably broken or incomplete) 4096k for esp8285
[env:dev_ESP8285_1024]
platform = espressif8266@1.5.0
lib_deps = ${common.lib_deps}
board_flash_mode = dout
platform = espressif8266
framework = arduino
board = esp8285
upload_speed=460800
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld -D PLUGIN_BUILD_TESTING -D PLUGIN_BUILD_DEV -DESP8285
#special patched version for PUYA flash chips, see https://github.com/letscontrolit/ESPEasy/issues/650
[env:dev_ESP8266PUYA_1024]
platform = espressif8266@1.5.0
lib_deps = ${common.lib_deps}
board_flash_mode = dout
framework = arduino
board = esp12e
upload_speed=460800
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld -D PLUGIN_BUILD_TESTING -D PLUGIN_BUILD_DEV -D FLASH_QUIRK_WRITE_0_TO_1
#special patched version for PUYA flash chips, see https://github.com/letscontrolit/ESPEasy/issues/650
[env:dev_ESP8266PUYA_1024_VCC]
platform = espressif8266@1.5.0
lib_deps = ${common.lib_deps}
board_flash_mode = dout
framework = arduino
board = esp12e
upload_speed=460800
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld -D PLUGIN_BUILD_TESTING -D PLUGIN_BUILD_DEV -D FLASH_QUIRK_WRITE_0_TO_1 -D FEATURE_ADC_VCC=true
+2 -11
View File
@@ -4,16 +4,7 @@ NEW="$1"
[ "$NEW" != "" ] || exit 1
echo "Creating release $NEW"
if git describe "$NEW" &>/dev/null; then
echo "Release already exists"
exit 1
fi
NEWBASE=`echo "$NEW"|cut -f1 -d'-'`
PREV=`git tag --sort=creatordate|grep "^$NEWBASE"|tail -1`
PREV=`git tag --sort=creatordate|tail -1`
############## update Release_notes.txt
NOTES="dist/Release_notes.txt"
@@ -43,5 +34,5 @@ git tag -a "$NEW" -m "`cat /tmp/tagmessage`"
################ push everything
git push origin HEAD
git push
git push --tags
+3 -2
View File
@@ -5,8 +5,9 @@
git pull
#new commits since last tag?
BRANCH=`git rev-parse --abbrev-ref HEAD`
if ! git describe --exact-match 2>/dev/null | grep "^$BRANCH"; then
if ! git describe --exact-match 2>/dev/null; then
BRANCH=`git rev-parse --abbrev-ref HEAD`
TAG="$BRANCH-`date +%Y%m%d`"
./release "$TAG"
fi
+43 -79
View File
@@ -127,7 +127,7 @@ void ExecuteCommand(byte source, const char *Line)
SendUDPCommand(Par1, (char*)event.c_str(), event.length());
}
}
#ifdef FEATURE_SD
if (strcasecmp_P(Command, PSTR("sdcard")) == 0)
{
success = true;
@@ -146,6 +146,7 @@ void ExecuteCommand(byte source, const char *Line)
Serial.println(fname.c_str());
SD.remove((char*)fname.c_str());
}
#endif
if (strcasecmp_P(Command, PSTR("lowmem")) == 0)
{
@@ -178,6 +179,21 @@ void ExecuteCommand(byte source, const char *Line)
delay(60000);
}
if (strcasecmp_P(Command, PSTR("accessinfo")) == 0)
{
success = true;
Serial.print(F("Allowed IP range : "));
Serial.println(describeAllowedIPrange());
}
if (strcasecmp_P(Command, PSTR("clearaccessblock")) == 0)
{
success = true;
clearAccessBlock();
Serial.print(F("Allowed IP range : "));
Serial.println(describeAllowedIPrange());
}
if (strcasecmp_P(Command, PSTR("meminfo")) == 0)
{
success = true;
@@ -197,14 +213,6 @@ void ExecuteCommand(byte source, const char *Line)
taskClear(Par1 - 1, true);
}
//quickly clear all tasks, without saving (used by test suite)
if (strcasecmp_P(Command, PSTR("TaskClearAll")) == 0)
{
success = true;
for (byte t=0; t<TASKS_MAX; t++)
taskClear(t, false);
}
if (strcasecmp_P(Command, PSTR("wdconfig")) == 0)
{
success = true;
@@ -358,19 +366,15 @@ void ExecuteCommand(byte source, const char *Line)
}
if (strcasecmp_P(Command, PSTR("Publish")) == 0 && WiFi.status() == WL_CONNECTED)
{
// ToDo TD-er: Not sure about this function, but at least it sends to an existing MQTTclient
int enabledMqttController = firstEnabledMQTTController();
if (enabledMqttController >= 0) {
success = true;
String event = Line;
event = event.substring(8);
int index = event.indexOf(',');
if (index > 0)
{
String topic = event.substring(0, index);
String value = event.substring(index + 1);
MQTTpublish(enabledMqttController, topic.c_str(), value.c_str(), Settings.MQTTRetainFlag);
}
success = true;
String event = Line;
event = event.substring(8);
int index = event.indexOf(',');
if (index > 0)
{
String topic = event.substring(0, index);
String value = event.substring(index + 1);
MQTTclient.publish(topic.c_str(), value.c_str(), Settings.MQTTRetainFlag);
}
}
@@ -382,17 +386,14 @@ void ExecuteCommand(byte source, const char *Line)
String port = parseString(strLine, 3);
int msgpos = getParamStartPos(strLine, 4);
String message = strLine.substring(msgpos);
IPAddress UDP_IP;
if(UDP_IP.fromString(ip)) {
portUDP.beginPacket(UDP_IP, port.toInt());
#if defined(ESP8266)
portUDP.write(message.c_str(), message.length());
#endif
#if defined(ESP32)
portUDP.write((uint8_t*)message.c_str(), message.length());
#endif
portUDP.endPacket();
}
byte ipaddress[4];
str2ip((char*)ip.c_str(), ipaddress);
IPAddress UDP_IP(ipaddress[0], ipaddress[1], ipaddress[2], ipaddress[3]);
portUDP.beginPacket(UDP_IP, port.toInt());
#if defined(ESP8266)
portUDP.write(message.c_str(), message.length());
#endif
portUDP.endPacket();
}
if (strcasecmp_P(Command, PSTR("SendToHTTP")) == 0 && WiFi.status() == WL_CONNECTED)
@@ -429,42 +430,6 @@ void ExecuteCommand(byte source, const char *Line)
}
}
// ****************************************
// special commands for Blynk
// ****************************************
#ifdef CPLUGIN_012
//FIXME: this should go to PLUGIN_WRITE in _C012.ino
if (strcasecmp_P(Command, PSTR("BlynkGet")) == 0)
{
byte first_enabled_blynk_controller = firstEnabledBlynkController();
if (first_enabled_blynk_controller == -1) {
status = F("Controller not enabled");
} else {
String strLine = Line;
strLine = strLine.substring(9);
int index = strLine.indexOf(',');
if (index > 0)
{
int index = strLine.lastIndexOf(',');
String blynkcommand = strLine.substring(index+1);
float value = 0;
if (Blynk_get(blynkcommand, first_enabled_blynk_controller, &value))
{
UserVar[(VARS_PER_TASK * (Par1 - 1)) + Par2 - 1] = value;
}
else
status = F("Error getting data");
}
else
{
if (!Blynk_get(strLine, first_enabled_blynk_controller))
{
status = F("Error getting data");
}
}
}
}
#endif
// ****************************************
// configure settings commands
@@ -542,7 +507,12 @@ void ExecuteCommand(byte source, const char *Line)
pinMode(0, INPUT);
pinMode(2, INPUT);
pinMode(15, INPUT);
ESP.reset();
#if defined(ESP8266)
ESP.reset();
#endif
#if defined(ESP32)
ESP.restart();
#endif
}
if (strcasecmp_P(Command, PSTR("Restart")) == 0)
@@ -562,13 +532,6 @@ void ExecuteCommand(byte source, const char *Line)
{
success = true;
ResetFactory();
#if defined(ESP8266)
ESP.reset();
#endif
#if defined(ESP32)
ESP.restart();
#endif
}
if (strcasecmp_P(Command, PSTR("Save")) == 0)
@@ -592,10 +555,9 @@ void ExecuteCommand(byte source, const char *Line)
if (strcasecmp_P(Command, PSTR("IP")) == 0)
{
success = true;
if (GetArgv(Line, TmpStr1, 2)) {
if (GetArgv(Line, TmpStr1, 2))
if (!str2ip(TmpStr1, Settings.IP))
Serial.println("?");
}
}
if (strcasecmp_P(Command, PSTR("Settings")) == 0)
@@ -628,6 +590,7 @@ void ExecuteCommand(byte source, const char *Line)
yield();
}
#ifdef FEATURE_SD
void printDirectory(File dir, int numTabs) {
while (true) {
@@ -651,3 +614,4 @@ void printDirectory(File dir, int numTabs) {
entry.close();
}
}
#endif
+71 -99
View File
@@ -7,6 +7,9 @@ void sendData(struct EventStruct *event)
if (Settings.UseRules)
createRuleEvents(event->TaskIndex);
if (Settings.GlobalSync && Settings.TaskDeviceGlobalSync[event->TaskIndex])
SendUDPTaskData(0, event->TaskIndex, event->TaskIndex);
if (Settings.UseValueLogger && Settings.InitSPI && Settings.Pin_sd_cs >= 0)
SendValueLogger(event->TaskIndex);
@@ -21,8 +24,7 @@ void sendData(struct EventStruct *event)
uint16_t delayms = Settings.MessageDelay - dif;
//this is logged nowhere else, so might as well disable it here also:
// addLog(LOG_LEVEL_DEBUG_MORE, String(F("CTRL : Message delay (ms): "))+delayms);
delayBackground(delayms);
delayBackground(delayms);
// unsigned long timer = millis() + delayms;
// while (!timeOutReached(timer))
@@ -36,19 +38,11 @@ void sendData(struct EventStruct *event)
{
event->ControllerIndex = x;
event->idx = Settings.TaskDeviceID[x][event->TaskIndex];
if (Settings.TaskDeviceSendData[event->ControllerIndex][event->TaskIndex] &&
Settings.ControllerEnabled[event->ControllerIndex] && Settings.Protocol[event->ControllerIndex])
if (Settings.TaskDeviceSendData[event->ControllerIndex][event->TaskIndex] && Settings.ControllerEnabled[event->ControllerIndex] && Settings.Protocol[event->ControllerIndex])
{
event->ProtocolIndex = getProtocolIndex(Settings.Protocol[event->ControllerIndex]);
if (validUserVar(event)) {
CPlugin_ptr[event->ProtocolIndex](CPLUGIN_PROTOCOL_SEND, event, dummyString);
} else {
String log = F("Invalid value detected for controller ");
String controllerName;
CPlugin_ptr[event->ProtocolIndex](CPLUGIN_GET_DEVICENAME, event, controllerName);
log += controllerName;
addLog(LOG_LEVEL_DEBUG, log);
}
CPlugin_ptr[event->ProtocolIndex](CPLUGIN_PROTOCOL_SEND, event, dummyString);
}
}
@@ -56,13 +50,6 @@ void sendData(struct EventStruct *event)
lastSend = millis();
}
boolean validUserVar(struct EventStruct *event) {
for (int i = 0; i < VARS_PER_TASK; ++i) {
const float f(UserVar[event->BaseVarIndex + i]);
if (!isValidFloat(f)) return false;
}
return true;
}
/*********************************************************************************************\
* Handle incoming MQTT messages
@@ -73,15 +60,10 @@ void callback(char* c_topic, byte* b_payload, unsigned int length) {
char c_payload[384];
statusLED(true);
int enabledMqttController = firstEnabledMQTTController();
if (enabledMqttController < 0) {
addLog(LOG_LEVEL_ERROR, F("MQTT : No enabled MQTT controller"));
return;
}
if ((length + 1) > sizeof(c_payload))
if (length>sizeof(c_payload)-1)
{
addLog(LOG_LEVEL_ERROR, F("MQTT : Ignored too big message"));
return;
}
//convert payload to string, and 0 terminate
@@ -105,7 +87,7 @@ void callback(char* c_topic, byte* b_payload, unsigned int length) {
struct EventStruct TempEvent;
TempEvent.String1 = c_topic;
TempEvent.String2 = c_payload;
byte ProtocolIndex = getProtocolIndex(Settings.Protocol[enabledMqttController]);
byte ProtocolIndex = getProtocolIndex(Settings.Protocol[0]);
CPlugin_ptr[ProtocolIndex](CPLUGIN_PROTOCOL_RECV, &TempEvent, dummyString);
}
@@ -113,14 +95,12 @@ void callback(char* c_topic, byte* b_payload, unsigned int length) {
/*********************************************************************************************\
* Connect to MQTT message broker
\*********************************************************************************************/
bool MQTTConnect(int controller_idx)
void MQTTConnect()
{
if (WiFi.status() != WL_CONNECTED) return;
ControllerSettingsStruct ControllerSettings;
LoadControllerSettings(controller_idx, (byte*)&ControllerSettings, sizeof(ControllerSettings));
if (!ControllerSettings.checkHostReachable(true))
return false;
if (MQTTclient.connected())
MQTTclient.disconnect();
LoadControllerSettings(0, (byte*)&ControllerSettings, sizeof(ControllerSettings)); // todo index is now fixed to 0
if (ControllerSettings.UseDNS) {
MQTTclient.setServer(ControllerSettings.getHost().c_str(), ControllerSettings.Port);
} else {
@@ -129,77 +109,78 @@ bool MQTTConnect(int controller_idx)
MQTTclient.setCallback(callback);
// MQTT needs a unique clientname to subscribe to broker
String clientid = F("ESPClient_");
clientid += WiFi.macAddress();
String clientid = Settings.Name; // clientid = %sysname%
if (Settings.Unit != 0) // set unit number to zero if don't want to add to clientid
{
clientid += Settings.Unit;
}
String subscribeTo = "";
String LWTTopic = ControllerSettings.Subscribe;
LWTTopic.replace(F("/#"), F("/status"));
parseSystemVariables(LWTTopic, false);
LWTTopic += F("/LWT"); // Extend the topic for status updates of connected/disconnected status.
LWTTopic.replace(F("%sysname%"), Settings.Name);
boolean MQTTresult = false;
uint8_t willQos = 0;
boolean willRetain = true;
for (byte x = 1; x < 3; x++)
{
String log = "";
boolean MQTTresult = false;
if ((SecuritySettings.ControllerUser[controller_idx] != 0) && (SecuritySettings.ControllerPassword[controller_idx] != 0)) {
MQTTresult = MQTTclient.connect(clientid.c_str(), SecuritySettings.ControllerUser[controller_idx], SecuritySettings.ControllerPassword[controller_idx],
LWTTopic.c_str(), willQos, willRetain, "Connection Lost");
} else {
MQTTresult = MQTTclient.connect(clientid.c_str(), LWTTopic.c_str(), willQos, willRetain, "Connection Lost");
}
yield();
if ((SecuritySettings.ControllerUser[0] != 0) && (SecuritySettings.ControllerPassword[0] != 0))
MQTTresult = MQTTclient.connect(clientid.c_str(), SecuritySettings.ControllerUser[0], SecuritySettings.ControllerPassword[0], LWTTopic.c_str(), 0, 1, "Connection Lost");
else
MQTTresult = MQTTclient.connect(clientid.c_str(), LWTTopic.c_str(), 0, 1, "Connection Lost");
if (!MQTTresult) {
addLog(LOG_LEVEL_ERROR, F("MQTT : Failed to connect to broker"));
return false;
}
MQTTclient_should_reconnect = false;
String log = F("MQTT : Connected to broker with client ID: ");
log += clientid;
addLog(LOG_LEVEL_INFO, log);
String subscribeTo = ControllerSettings.Subscribe;
parseSystemVariables(subscribeTo, false);
MQTTclient.subscribe(subscribeTo.c_str());
log = F("Subscribed to: ");
log += subscribeTo;
addLog(LOG_LEVEL_INFO, log);
if (MQTTclient.publish(LWTTopic.c_str(), "Connected", 1)) {
if (Settings.UseRules)
if (MQTTresult)
{
String event = F("MQTT#Connected");
rulesProcessing(event);
log = F("MQTT : ClientID ");
log += clientid;
log += " connected to broker";
addLog(LOG_LEVEL_INFO, log);
subscribeTo = ControllerSettings.Subscribe;
subscribeTo.replace(F("%sysname%"), Settings.Name);
MQTTclient.subscribe(subscribeTo.c_str());
log = F("Subscribed to: ");
log += subscribeTo;
addLog(LOG_LEVEL_INFO, log);
MQTTclient.publish(LWTTopic.c_str(), "Connected", 1);
statusLED(true);
break; // end loop if succesfull
}
statusLED(true);
return true; // end loop if succesfull
else
{
log = F("MQTT : ClientID ");
log += clientid;
log +=" failed to connected to broker";
addLog(LOG_LEVEL_ERROR, log);
}
delay(500);
}
return false;
}
/*********************************************************************************************\
* Check connection MQTT message broker
\*********************************************************************************************/
bool MQTTCheck(int controller_idx)
void MQTTCheck()
{
byte ProtocolIndex = getProtocolIndex(Settings.Protocol[controller_idx]);
byte ProtocolIndex = getProtocolIndex(Settings.Protocol[0]);
if (Protocol[ProtocolIndex].usesMQTT)
{
if (MQTTclient_should_reconnect || !WiFiConnected(10) || !MQTTclient.connected())
if (!MQTTclient.connected() || WiFi.status() != WL_CONNECTED)
{
if (MQTTclient_should_reconnect) {
addLog(LOG_LEVEL_ERROR, F("MQTT : Intentional reconnect"));
} else {
addLog(LOG_LEVEL_ERROR, F("MQTT : Connection lost"));
connectionFailures += 2;
addLog(LOG_LEVEL_ERROR, F("MQTT : Connection lost"));
connectionFailures += 2;
MQTTclient.disconnect();
if (WiFi.status() == WL_CONNECTED) {
delay(1000);
MQTTConnect();
}
return MQTTConnect(controller_idx);
} else if (connectionFailures) {
connectionFailures--;
}
else if (connectionFailures)
connectionFailures--;
}
// When no MQTT protocol is enabled, all is fine.
return true;
}
@@ -224,13 +205,6 @@ void SendStatus(byte source, String status)
}
}
boolean MQTTpublish(int controller_idx, const char* topic, const char* payload, boolean retained)
{
if (MQTTclient.publish(topic, payload, retained))
return true;
addLog(LOG_LEVEL_DEBUG, F("MQTT : publish failed"));
return false;
}
/*********************************************************************************************\
* Send status info back to channel where request came from
@@ -238,12 +212,10 @@ boolean MQTTpublish(int controller_idx, const char* topic, const char* payload,
void MQTTStatus(String& status)
{
ControllerSettingsStruct ControllerSettings;
int enabledMqttController = firstEnabledMQTTController();
if (enabledMqttController >= 0) {
LoadControllerSettings(enabledMqttController, (byte*)&ControllerSettings, sizeof(ControllerSettings));
String pubname = ControllerSettings.Subscribe;
pubname.replace(F("/#"), F("/status"));
parseSystemVariables(pubname, false);
MQTTpublish(enabledMqttController, pubname.c_str(), status.c_str(),Settings.MQTTRetainFlag);
}
LoadControllerSettings(0, (byte*)&ControllerSettings, sizeof(ControllerSettings)); // todo index is now fixed to 0
String pubname = ControllerSettings.Subscribe;
pubname.replace(F("/#"), F("/status"));
pubname.replace(F("%sysname%"), Settings.Name);
MQTTclient.publish(pubname.c_str(), status.c_str(),Settings.MQTTRetainFlag);
}
-129
View File
@@ -1,129 +0,0 @@
/*********************************************************************************************\
Convert bearing in degree to bearing string
\*********************************************************************************************/
String getBearing(int degrees)
{
const __FlashStringHelper* bearing[] = {
F("N"),
F("NNE"),
F("NE"),
F("ENE"),
F("E"),
F("ESE"),
F("SE"),
F("SSE"),
F("S"),
F("SSW"),
F("SW"),
F("WSW"),
F("W"),
F("WNW"),
F("NW"),
F("NNW")
};
int nr_directions = (int) (sizeof(bearing)/sizeof(bearing[0]));
float stepsize = (360.0 / nr_directions);
if (degrees < 0) { degrees += 360; } // Allow for bearing -360 .. 359
int bearing_idx=int((degrees + (stepsize / 2.0)) / stepsize) % nr_directions;
if (bearing_idx < 0)
return("");
else
return(bearing[bearing_idx]);
}
float CelsiusToFahrenheit(float celsius) {
return celsius * (9.0 / 5.0) + 32;
}
int m_secToBeaufort(float m_per_sec) {
if (m_per_sec < 0.3) return 0;
if (m_per_sec < 1.6) return 1;
if (m_per_sec < 3.4) return 2;
if (m_per_sec < 5.5) return 3;
if (m_per_sec < 8.0) return 4;
if (m_per_sec < 10.8) return 5;
if (m_per_sec < 13.9) return 6;
if (m_per_sec < 17.2) return 7;
if (m_per_sec < 20.8) return 8;
if (m_per_sec < 24.5) return 9;
if (m_per_sec < 28.5) return 10;
if (m_per_sec < 32.6) return 11;
return 12;
}
String centimeterToImperialLength(float cm) {
return millimeterToImperialLength(cm * 10.0);
}
String millimeterToImperialLength(float mm) {
float inches = mm / 25.4;
int feet = inches /12;
inches = inches - (feet * 12);
String result;
result.reserve(10);
if (feet != 0) {
result += feet;
result += '\'';
}
result += toString(inches,1);
result += '"';
return result;
}
float minutesToDay(int minutes) {
return minutes / 1440.0;
}
String minutesToDayHour(int minutes) {
int days = minutes / 1440;
int hours = (minutes % 1440) / 60;
char TimeString[6]; //5 digits plus the null char
sprintf_P(TimeString, PSTR("%d%c%02d%c"), days, 'd', hours, 'h');
return TimeString;
}
String minutesToDayHourMinute(int minutes) {
int days = minutes / 1440;
int hours = (minutes % 1440) / 60;
int mins = (minutes % 1440) % 60;
char TimeString[20];
sprintf_P(TimeString, PSTR("%d%c%02d%c%02d%c"), days, 'd', hours, 'h', mins, 'm');
return TimeString;
}
String secondsToDayHourMinuteSecond(int seconds) {
int sec = seconds % 60;
int minutes = seconds / 60;
int days = minutes / 1440;
int hours = (minutes % 1440) / 60;
int mins = (minutes % 1440) % 60;
char TimeString[20];
sprintf_P(TimeString, PSTR("%d%c%02d%c%02d%c%02d"), days, 'd', hours, ':', mins, ':', sec);
return TimeString;
}
/********************************************************************************************\
In memory convert float to long
\*********************************************************************************************/
unsigned long float2ul(float f)
{
unsigned long ul;
memcpy(&ul, &f, 4);
return ul;
}
/********************************************************************************************\
In memory convert long to float
\*********************************************************************************************/
float ul2float(unsigned long ul)
{
float f;
memcpy(&f, &ul, 4);
return f;
}
-42
View File
@@ -1,42 +0,0 @@
/*
To modify the stock configuration without changing the EspEasy.ino file :
1) rename this file to "Custom.h" (It is ignored by Git)
2) define your own settings below
3) define USE_CUSTOM_H as a build flags. ie : export PLATFORMIO_BUILD_FLAGS="'-DUSE_CUSTOM_H'"
*/
// make the compiler show a warning to confirm that this file is inlcuded
#warning "**** Using Settings from Custom.h File ***"
/*
#######################################################################################################
Your Own Default Settings
#######################################################################################################
You can basically ovveride ALL macro defined in ESPEasy.ino.
Don't forget to first #undef each existing #define that you add below.
Here are some examples:
*/
#undef DEFAULT_NAME
#define DEFAULT_NAME "MyEspEasyDevice" // Enter your device friendly name
#undef DEFAULT_SSID
#define DEFAULT_SSID "MyHomeSSID" // Enter your network SSID
#undef DEFAULT_KEY
#define DEFAULT_KEY "MySuperSecretPassword" // Enter your network WPA key
#undef DEFAULT_AP_KEY
#define DEFAULT_AP_KEY "MyOwnConfigPassword" // Enter network WPA key for AP (config) mode
#ifdef BUILD_GIT
#undef BUILD_GIT
#endif
#define BUILD_GIT "MyBuildNum"
@@ -22,10 +22,6 @@ SOFTWARE.
See more at http://blog.squix.ch
*/
#ifndef DIALOG_PLAIN_FONT_H
#define DIALOG_PLAIN_FONT_H
// OLED library version >= 3.0.0
// Created by http://oleddisplay.squix.ch/ Consider a donation
// In case of problems make sure that you are using the font file with the correct version!
@@ -485,6 +481,3 @@ const char Dialog_plain_12[] PROGMEM = {
0x00,0x00,0xFC,0x7F,0x40,0x04,0x20,0x08,0x20,0x08,0x60,0x0C,0xC0,0x07, // 254
0x00,0x00,0xE0,0x40,0x04,0x47,0x00,0x38,0x84,0x07,0xE0 // 255
};
#endif
-985
View File
@@ -1,985 +0,0 @@
#ifndef ESPEASY_GLOBALS_H_
#define ESPEASY_GLOBALS_H_
// ********************************************************************************
// User specific configuration
// ********************************************************************************
// Set default configuration settings if you want (not mandatory)
// You can always change these during runtime and save to eeprom
// After loading firmware, issue a 'reset' command to load the defaults.
// --- Basic Config Settings ------------------------------------------------------------------------
#define DEFAULT_NAME "ESP_Easy" // Enter your device friendly name
#define UNIT 0 // Unit Number
#define DEFAULT_DELAY 60 // Sleep Delay in seconds
// --- Wifi AP Mode (when your Wifi Network is not reachable) ----------------------------------------
#define DEFAULT_AP_IP 192,168,4,1 // Enter IP address (comma separated) for AP (config) mode
#define DEFAULT_AP_KEY "configesp" // Enter network WPA key for AP (config) mode
// --- Wifi Client Mode -----------------------------------------------------------------------------
#define DEFAULT_SSID "ssid" // Enter your Wifi network SSID
#define DEFAULT_KEY "wpakey" // Enter your Wifi network WPA key
#define DEFAULT_USE_STATIC_IP false // (true|false) enabled or disabled static IP
#define DEFAULT_IP "192.168.0.50" // Enter your IP address
#define DEFAULT_DNS "192.168.0.1" // Enter your DNS
#define DEFAULT_GW "192.168.0.1" // Enter your Gateway
#define DEFAULT_SUBNET "255.255.255.0" // Enter your Subnet
#define DEFAULT_WIFI_CONNECTION_TIMEOUT 10000 // minimum timeout in ms for WiFi to be connected.
// --- Default Controller ------------------------------------------------------------------------------
#define DEFAULT_CONTROLLER false // true or false enabled or disabled, set 1st controller defaults
// using a default template, you also need to set a DEFAULT PROTOCOL to a suitable MQTT protocol !
#define DEFAULT_PUB "sensors/espeasy/%sysname%/%tskname%/%valname%" // Enter your pub
#define DEFAULT_SUB "sensors/espeasy/%sysname%/#" // Enter your sub
#define DEFAULT_SERVER "192.168.0.8" // Enter your Server IP address
#define DEFAULT_PORT 8080 // Enter your Server port value
#define DEFAULT_PROTOCOL 1 // Protocol used for controller communications
// 1 = Domoticz HTTP
// 2 = Domoticz MQTT
// 3 = Nodo Telnet
// 4 = ThingSpeak
// 5 = OpenHAB MQTT
// 6 = PiDome MQTT
// 7 = EmonCMS
// 8 = Generic HTTP
// 9 = FHEM HTTP
// --- Advanced Settings ---------------------------------------------------------------------------------
#define DEFAULT_USE_RULES false // (true|false) Enable Rules?
#define DEFAULT_MQTT_RETAIN false // (true|false) Retain MQTT messages?
#define DEFAULT_MQTT_DELAY 1000 // Time in milliseconds to retain MQTT messages
#define DEFAULT_USE_NTP false // (true|false) Use NTP Server
#define DEFAULT_NTP_HOST "" // NTP Server Hostname
#define DEFAULT_TIME_ZONE 0 // Time Offset (in minutes)
#define DEFAULT_USE_DST false // (true|false) Use Daily Time Saving
#define LOG_TO_SERIAL 1
#define LOG_TO_SYSLOG 2
#define LOG_TO_WEBLOG 3
#define LOG_TO_SDCARD 4
#define DEFAULT_SYSLOG_IP "" // Syslog IP Address
#define DEFAULT_SYSLOG_LEVEL 0 // Syslog Log Level
#define DEFAULT_SERIAL_LOG_LEVEL LOG_LEVEL_INFO // Serial Log Level
#define DEFAULT_WEB_LOG_LEVEL LOG_LEVEL_INFO // Web Log Level
#define DEFAULT_SD_LOG_LEVEL 0 // SD Card Log Level
#define DEFAULT_USE_SD_LOG false // (true|false) Enable Logging to the SD card
#define DEFAULT_USE_SERIAL true // (true|false) Enable Logging to the Serial Port
#define DEFAULT_SERIAL_BAUD 115200 // Serial Port Baud Rate
/*
// --- Experimental Advanced Settings (NOT ACTIVES at this time) ------------------------------------
#define DEFAULT_USE_GLOBAL_SYNC false // (true|false)
#define DEFAULT_SYNC_UDP_PORT 0 //
#define DEFAULT_IP_OCTET 0 //
#define DEFAULT_WD_IC2_ADDRESS 0 //
#define DEFAULT_USE_SSDP false // (true|false)
#define DEFAULT_CON_FAIL_THRES 0 //
#define DEFAULT_I2C_CLOCK_LIMIT 0 //
*/
// Enable FEATURE_ADC_VCC to measure supply voltage using the analog pin
// Please note that the TOUT pin has to be disconnected in this mode
// Use the "System Info" device to read the VCC value
#ifndef FEATURE_ADC_VCC
#define FEATURE_ADC_VCC false
#endif
//enable Arduino OTA updating.
//Note: This adds around 10kb to the firmware size, and 1kb extra ram.
// #define FEATURE_ARDUINO_OTA
//enable mDNS mode (adds about 6kb ram and some bytes IRAM)
// #define FEATURE_MDNS
//enable reporting status to ESPEasy developers.
//this informs us of crashes and stability issues.
// not finished yet!
// #define FEATURE_REPORTING
//Select which plugin sets you want to build.
//These are normally automaticly set via the Platformio build environment.
//If you use ArduinoIDE you might need to uncomment some of them, depending on your needs
//If you dont select any, a version with a minimal number of plugins will be biult for 512k versions.
//(512k is NOT finsihed or tested yet as of v2.0.0-dev6)
//build all the normal stable plugins (on by default)
#define PLUGIN_BUILD_NORMAL
//build all plugins that are in test stadium
//#define PLUGIN_BUILD_TESTING
//build all plugins that still are being developed and are broken or incomplete
//#define PLUGIN_BUILD_DEV
// ********************************************************************************
// DO NOT CHANGE ANYTHING BELOW THIS LINE
// ********************************************************************************
#include "core_version.h"
#ifndef ARDUINO_ESP8266_RELEASE_2_3_0
#error ESPEasy v2.0 only support Arduino core 2.3.0. (Use the ESPEasy development branch to fix this)
#endif
#define ESP_PROJECT_PID 2016110801L
#define VERSION 2 // config file version (not ESPEasy version). increase if you make incompatible changes to config system.
#define BUILD 20000 // git version 2.0.0
#define BUILD_NOTES " - Mega"
#ifndef BUILD_GIT
#define BUILD_GIT "(custom)"
#endif
#define MAX_FLASHWRITES_PER_DAY 100 // per 24 hour window
#define NODE_TYPE_ID_ESP_EASY_STD 1
#define NODE_TYPE_ID_ESP_EASYM_STD 17
#define NODE_TYPE_ID_ESP_EASY32_STD 33
#define NODE_TYPE_ID_ARDUINO_EASY_STD 65
#define NODE_TYPE_ID_NANO_EASY_STD 81
#define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASYM_STD
#define PLUGIN_INIT_ALL 1
#define PLUGIN_INIT 2
#define PLUGIN_READ 3
#define PLUGIN_ONCE_A_SECOND 4
#define PLUGIN_TEN_PER_SECOND 5
#define PLUGIN_DEVICE_ADD 6
#define PLUGIN_EVENTLIST_ADD 7
#define PLUGIN_WEBFORM_SAVE 8
#define PLUGIN_WEBFORM_LOAD 9
#define PLUGIN_WEBFORM_SHOW_VALUES 10
#define PLUGIN_GET_DEVICENAME 11
#define PLUGIN_GET_DEVICEVALUENAMES 12
#define PLUGIN_WRITE 13
#define PLUGIN_EVENT_OUT 14
#define PLUGIN_WEBFORM_SHOW_CONFIG 15
#define PLUGIN_SERIAL_IN 16
#define PLUGIN_UDP_IN 17
#define PLUGIN_CLOCK_IN 18
#define PLUGIN_TIMER_IN 19
#define PLUGIN_FIFTY_PER_SECOND 20
#define PLUGIN_SET_CONFIG 21
#define PLUGIN_GET_DEVICEGPIONAMES 22
#define PLUGIN_EXIT 23
#define PLUGIN_GET_CONFIG 24
#define CPLUGIN_PROTOCOL_ADD 1
#define CPLUGIN_PROTOCOL_TEMPLATE 2
#define CPLUGIN_PROTOCOL_SEND 3
#define CPLUGIN_PROTOCOL_RECV 4
#define CPLUGIN_GET_DEVICENAME 5
#define CPLUGIN_WEBFORM_SAVE 6
#define CPLUGIN_WEBFORM_LOAD 7
#define CPLUGIN_GET_PROTOCOL_DISPLAY_NAME 8
#define CPLUGIN_TASK_CHANGE_NOTIFICATION 9
#define CPLUGIN_INIT 10
#define CPLUGIN_UDP_IN 11
#define CONTROLLER_HOSTNAME 1
#define CONTROLLER_IP 2
#define CONTROLLER_PORT 3
#define CONTROLLER_USER 4
#define CONTROLLER_PASS 5
#define CONTROLLER_SUBSCRIBE 6
#define CONTROLLER_PUBLISH 7
#define NPLUGIN_PROTOCOL_ADD 1
#define NPLUGIN_GET_DEVICENAME 2
#define NPLUGIN_WEBFORM_SAVE 3
#define NPLUGIN_WEBFORM_LOAD 4
#define NPLUGIN_WRITE 5
#define NPLUGIN_NOTIFY 6
#define NPLUGIN_NOT_FOUND 255
#define LOG_LEVEL_ERROR 1
#define LOG_LEVEL_INFO 2
#define LOG_LEVEL_DEBUG 3
#define LOG_LEVEL_DEBUG_MORE 4
#define LOG_LEVEL_DEBUG_DEV 9 // use for testing/debugging only, not for regular use
#define CMD_REBOOT 89
#define CMD_WIFI_DISCONNECT 135
#if defined(PLUGIN_BUILD_TESTING) || defined(PLUGIN_BUILD_DEV)
#define DEVICES_MAX 72
#else
#define DEVICES_MAX 64
#endif
#if defined(ESP8266)
#define TASKS_MAX 12 // max 12!
#endif
#if defined(ESP32)
#define TASKS_MAX 32
#endif
#define CONTROLLER_MAX 3 // max 4!
#define NOTIFICATION_MAX 3 // max 4!
#define VARS_PER_TASK 4
#define PLUGIN_MAX DEVICES_MAX
#define PLUGIN_CONFIGVAR_MAX 8
#define PLUGIN_CONFIGFLOATVAR_MAX 4
#define PLUGIN_CONFIGLONGVAR_MAX 4
#define PLUGIN_EXTRACONFIGVAR_MAX 16
#define CPLUGIN_MAX 16
#define NPLUGIN_MAX 4
#define UNIT_MAX 32 // Only relevant for UDP unicast message 'sweeps' and the nodelist.
#define RULES_TIMER_MAX 8
#define SYSTEM_TIMER_MAX 8
#define SYSTEM_CMD_TIMER_MAX 2
#define PINSTATE_TABLE_MAX 32
#define RULES_MAX_SIZE 2048
#define RULES_MAX_NESTING_LEVEL 3
#define RULESETS_MAX 4
#define RULES_BUFFER_SIZE 64
#define PIN_MODE_UNDEFINED 0
#define PIN_MODE_INPUT 1
#define PIN_MODE_OUTPUT 2
#define PIN_MODE_PWM 3
#define PIN_MODE_SERVO 4
#define SEARCH_PIN_STATE true
#define NO_SEARCH_PIN_STATE false
#define DEVICE_TYPE_SINGLE 1 // connected through 1 datapin
#define DEVICE_TYPE_DUAL 2 // connected through 2 datapins
#define DEVICE_TYPE_TRIPLE 3 // connected through 3 datapins
#define DEVICE_TYPE_ANALOG 10 // AIN/tout pin
#define DEVICE_TYPE_I2C 20 // connected through I2C
#define DEVICE_TYPE_DUMMY 99 // Dummy device, has no physical connection
#define SENSOR_TYPE_SINGLE 1
#define SENSOR_TYPE_TEMP_HUM 2
#define SENSOR_TYPE_TEMP_BARO 3
#define SENSOR_TYPE_TEMP_HUM_BARO 4
#define SENSOR_TYPE_DUAL 5
#define SENSOR_TYPE_TRIPLE 6
#define SENSOR_TYPE_QUAD 7
#define SENSOR_TYPE_SWITCH 10
#define SENSOR_TYPE_DIMMER 11
#define SENSOR_TYPE_LONG 20
#define SENSOR_TYPE_WIND 21
#define VALUE_SOURCE_SYSTEM 1
#define VALUE_SOURCE_SERIAL 2
#define VALUE_SOURCE_HTTP 3
#define VALUE_SOURCE_MQTT 4
#define VALUE_SOURCE_UDP 5
#define BOOT_CAUSE_MANUAL_REBOOT 0
#define BOOT_CAUSE_COLD_BOOT 1
#define BOOT_CAUSE_DEEP_SLEEP 2
#define BOOT_CAUSE_EXT_WD 10
#define DAT_TASKS_SIZE 2048
#define DAT_TASKS_CUSTOM_OFFSET 1024
#define DAT_CUSTOM_CONTROLLER_SIZE 1024
#define DAT_CONTROLLER_SIZE 1024
#define DAT_NOTIFICATION_SIZE 1024
#define DAT_OFFSET_TASKS 4096 // each task = 2k, (1024 basic + 1024 bytes custom), 12 max
#define DAT_OFFSET_CONTROLLER 28672 // each controller = 1k, 4 max
#define DAT_OFFSET_CUSTOM_CONTROLLER 32768 // each custom controller config = 1k, 4 max.
/*
To modify the stock configuration without changing this repo file :
- define USE_CUSTOM_H as a build flags. ie : export PLATFORMIO_BUILD_FLAGS="'-DUSE_CUSTOM_H'"
- add a "Custom.h" file in this folder.
*/
#ifdef USE_CUSTOM_H
#include "Custom.h"
#endif
#define FILE_CONFIG "config.dat"
#define FILE_SECURITY "security.dat"
#define FILE_NOTIFICATION "notification.dat"
#define FILE_RULES "rules1.dat"
#include "ESPEasyTimeTypes.h"
#include "lwip/tcp_impl.h"
#include <ESP8266WiFi.h>
#include <ESP8266Ping.h>
#include <DNSServer.h>
#include <WiFiUdp.h>
#include <ESP8266WebServer.h>
#ifdef FEATURE_MDNS
#include <ESP8266mDNS.h>
#endif
#include <Wire.h>
#include <SPI.h>
#include <PubSubClient.h>
// #include <ArduinoJson.h>
// #include <LiquidCrystal_I2C.h>
#include <Servo.h>
#define FS_NO_GLOBALS
#include <FS.h>
#include <SD.h>
#include <ESP8266HTTPUpdateServer.h>
ESP8266HTTPUpdateServer httpUpdater(true);
#include <base64.h>
#if FEATURE_ADC_VCC
ADC_MODE(ADC_VCC);
#endif
#ifndef LWIP_OPEN_SRC
#define LWIP_OPEN_SRC
#endif
#include "lwip/opt.h"
#include "lwip/udp.h"
#include "lwip/igmp.h"
#include "include/UdpContext.h"
#include "limits.h"
extern "C" {
#include "user_interface.h"
}
#ifdef FEATURE_ARDUINO_OTA
#include <ArduinoOTA.h>
#include <ESP8266mDNS.h>
bool ArduinoOTAtriggered=false;
#endif
// Setup DNS, only used if the ESP has no valid WiFi config
const byte DNS_PORT = 53;
IPAddress apIP(DEFAULT_AP_IP);
DNSServer dnsServer;
#ifdef FEATURE_MDNS
MDNSResponder mdns;
#endif
// MQTT client
WiFiClient mqtt;
PubSubClient MQTTclient(mqtt);
bool MQTTclient_should_reconnect = true;
// WebServer
ESP8266WebServer WebServer(80);
// udp protocol stuff (syslog, global sync, node info list, ntp time)
WiFiUDP portUDP;
// Forward declarations.
bool WiFiConnected(uint32_t timeout_ms);
bool hostReachable(const IPAddress& ip);
bool hostReachable(const String& hostname);
extern "C" {
#include "spi_flash.h"
}
extern "C" uint32_t _SPIFFS_start;
extern "C" uint32_t _SPIFFS_end;
extern "C" uint32_t _SPIFFS_page;
extern "C" uint32_t _SPIFFS_block;
struct SecurityStruct
{
SecurityStruct() {
memset(WifiSSID, 0, sizeof(WifiSSID));
memset(WifiKey, 0, sizeof(WifiKey));
memset(WifiSSID2, 0, sizeof(WifiSSID2));
memset(WifiKey2, 0, sizeof(WifiKey2));
memset(WifiAPKey, 0, sizeof(WifiAPKey));
for (byte i = 0; i < CONTROLLER_MAX; ++i) {
memset(ControllerUser[i], 0, sizeof(ControllerUser[i]));
memset(ControllerPassword[i], 0, sizeof(ControllerPassword[i]));
}
memset(Password, 0, sizeof(Password));
}
char WifiSSID[32];
char WifiKey[64];
char WifiSSID2[32];
char WifiKey2[64];
char WifiAPKey[64];
char ControllerUser[CONTROLLER_MAX][26];
char ControllerPassword[CONTROLLER_MAX][64];
char Password[26];
//its safe to extend this struct, up to 4096 bytes, default values in config are 0
} SecuritySettings;
struct SettingsStruct
{
SettingsStruct() :
PID(0), Version(0), Build(0), IP_Octet(0), Unit(0), Delay(0),
Pin_i2c_sda(-1), Pin_i2c_scl(-1), Pin_status_led(-1), Pin_sd_cs(-1),
UDPPort(0), SyslogLevel(0), SerialLogLevel(0), WebLogLevel(0), SDLogLevel(0),
BaudRate(0), MessageDelay(0), deepSleep(0),
CustomCSS(false), DST(false), WDI2CAddress(0),
UseRules(false), UseSerial(false), UseSSDP(false), UseNTP(false),
WireClockStretchLimit(0), ConnectionFailuresThreshold(0),
TimeZone(0), MQTTRetainFlag(false), InitSPI(false),
Pin_status_led_Inversed(false), deepSleepOnFail(false), UseValueLogger(false),
DST_Start(0), DST_End(0)
{
for (byte i = 0; i < CONTROLLER_MAX; ++i) {
Protocol[i] = 0;
ControllerEnabled[i] = false;
for (byte task = 0; task < TASKS_MAX; ++task) {
TaskDeviceID[i][task] = 0;
TaskDeviceSendData[i][task] = false;
}
}
for (byte task = 0; task < TASKS_MAX; ++task) {
TaskDeviceNumber[task] = 0;
OLD_TaskDeviceID[task] = 0;
TaskDevicePin1PullUp[task] = false;
for (byte cv = 0; cv < PLUGIN_CONFIGVAR_MAX; ++cv) {
TaskDevicePluginConfig[task][cv] = 0;
}
TaskDevicePin1Inversed[task] = false;
for (byte cv = 0; cv < PLUGIN_CONFIGFLOATVAR_MAX; ++cv) {
TaskDevicePluginConfigFloat[task][cv] = 0.0;
}
for (byte cv = 0; cv < PLUGIN_CONFIGLONGVAR_MAX; ++cv) {
TaskDevicePluginConfigLong[task][cv] = 0;
}
OLD_TaskDeviceSendData[task] = false;
TaskDeviceGlobalSync[task] = false;
TaskDeviceDataFeed[task] = 0;
TaskDeviceTimer[task] = 0;
TaskDeviceEnabled[task] = false;
}
}
unsigned long PID;
int Version;
int16_t Build;
byte IP[4];
byte Gateway[4];
byte Subnet[4];
byte DNS[4];
byte IP_Octet;
byte Unit;
char Name[26];
char NTPHost[64];
unsigned long Delay;
int8_t Pin_i2c_sda;
int8_t Pin_i2c_scl;
int8_t Pin_status_led;
int8_t Pin_sd_cs;
int8_t PinBootStates[17];
byte Syslog_IP[4];
unsigned int UDPPort;
byte SyslogLevel;
byte SerialLogLevel;
byte WebLogLevel;
byte SDLogLevel;
unsigned long BaudRate;
unsigned long MessageDelay;
byte deepSleep;
boolean CustomCSS;
boolean DST;
byte WDI2CAddress;
boolean UseRules;
boolean UseSerial;
boolean UseSSDP;
boolean UseNTP;
unsigned long WireClockStretchLimit;
boolean _GlobalSync; // obsolete!
unsigned long ConnectionFailuresThreshold;
int16_t TimeZone;
boolean MQTTRetainFlag;
boolean InitSPI;
byte Protocol[CONTROLLER_MAX];
byte Notification[NOTIFICATION_MAX]; //notifications, point to a NPLUGIN id
byte TaskDeviceNumber[TASKS_MAX];
unsigned int OLD_TaskDeviceID[TASKS_MAX];
union {
struct {
int8_t TaskDevicePin1[TASKS_MAX];
int8_t TaskDevicePin2[TASKS_MAX];
int8_t TaskDevicePin3[TASKS_MAX];
byte TaskDevicePort[TASKS_MAX];
};
int8_t TaskDevicePin[4][TASKS_MAX];
};
boolean TaskDevicePin1PullUp[TASKS_MAX];
int16_t TaskDevicePluginConfig[TASKS_MAX][PLUGIN_CONFIGVAR_MAX];
boolean TaskDevicePin1Inversed[TASKS_MAX];
float TaskDevicePluginConfigFloat[TASKS_MAX][PLUGIN_CONFIGFLOATVAR_MAX];
long TaskDevicePluginConfigLong[TASKS_MAX][PLUGIN_CONFIGLONGVAR_MAX];
boolean OLD_TaskDeviceSendData[TASKS_MAX];
boolean TaskDeviceGlobalSync[TASKS_MAX];
byte TaskDeviceDataFeed[TASKS_MAX];
unsigned long TaskDeviceTimer[TASKS_MAX];
boolean TaskDeviceEnabled[TASKS_MAX];
boolean ControllerEnabled[CONTROLLER_MAX];
boolean NotificationEnabled[NOTIFICATION_MAX];
unsigned int TaskDeviceID[CONTROLLER_MAX][TASKS_MAX];
boolean TaskDeviceSendData[CONTROLLER_MAX][TASKS_MAX];
boolean Pin_status_led_Inversed;
boolean deepSleepOnFail;
boolean UseValueLogger;
uint16_t DST_Start;
uint16_t DST_End;
//its safe to extend this struct, up to several bytes, default values in config are 0
//look in misc.ino how config.dat is used because also other stuff is stored in it at different offsets.
//TODO: document config.dat somewhere here
} Settings;
struct ControllerSettingsStruct
{
ControllerSettingsStruct() : UseDNS(false), Port(0) {
for (byte i = 0; i < 4; ++i) {
IP[i] = 0;
}
memset(HostName, 0, sizeof(HostName));
memset(Publish, 0, sizeof(Publish));
memset(Subscribe, 0, sizeof(Subscribe));
}
boolean UseDNS;
byte IP[4];
unsigned int Port;
char HostName[65];
char Publish[129];
char Subscribe[129];
IPAddress getIP() const {
IPAddress host(IP[0], IP[1], IP[2], IP[3]);
return host;
}
String getHost() const {
if (UseDNS) {
return HostName;
}
return getIP().toString();
}
void setHostname(const String& controllerhostname) {
strncpy(HostName, controllerhostname.c_str(), sizeof(HostName));
updateIPcache();
}
boolean checkHostReachable(bool quick) {
if (!WiFiConnected(10)) {
return false; // Not connected, so no use in wasting time to connect to a host.
}
if (quick && ipSet()) return true;
if (UseDNS) {
if (!updateIPcache()) {
return false;
}
}
return hostReachable(getIP());
}
boolean connectToHost(WiFiClient &client) {
if (!checkHostReachable(true)) {
return false; // Host not reachable
}
byte retry = 2;
bool connected = false;
while (retry > 0 && !connected) {
--retry;
connected = client.connect(getIP(), Port);
if (connected) return true;
if (!checkHostReachable(false))
return false;
}
return false;
}
int beginPacket(WiFiUDP &client) {
if (!checkHostReachable(true)) {
return 0; // Host not reachable
}
byte retry = 2;
int connected = 0;
while (retry > 0 && !connected) {
--retry;
connected = client.beginPacket(getIP(), Port);
if (connected != 0) return connected;
if (!checkHostReachable(false))
return false;
delay(10);
}
return false;
}
String getHostPortString() const {
String result = getHost();
result += ":";
result += Port;
return result;
}
private:
bool ipSet() {
for (byte i = 0; i < 4; ++i) {
if (IP[i] != 0) return true;
}
return false;
}
bool updateIPcache() {
if (!UseDNS) {
return true;
}
IPAddress tmpIP;
if (WiFi.hostByName(HostName, tmpIP)) {
for (byte x = 0; x < 4; x++) {
IP[x] = tmpIP[x];
}
return true;
}
return false;
}
};
struct NotificationSettingsStruct
{
NotificationSettingsStruct() : Port(0), Pin1(0), Pin2(0) {
memset(Server, 0, sizeof(Server));
memset(Domain, 0, sizeof(Domain));
memset(Sender, 0, sizeof(Sender));
memset(Receiver, 0, sizeof(Receiver));
memset(Subject, 0, sizeof(Subject));
memset(Body, 0, sizeof(Body));
memset(User, 0, sizeof(User));
memset(Pass, 0, sizeof(Pass));
}
char Server[65];
unsigned int Port;
char Domain[65];
char Sender[65];
char Receiver[65];
char Subject[129];
char Body[513];
byte Pin1;
byte Pin2;
char User[49];
char Pass[33];
//its safe to extend this struct, up to 4096 bytes, default values in config are 0
};
struct ExtraTaskSettingsStruct
{
ExtraTaskSettingsStruct() : TaskIndex(0) {
TaskDeviceName[0] = 0;
for (byte i = 0; i < VARS_PER_TASK; ++i) {
for (byte j = 0; j < 41; ++j) {
TaskDeviceFormula[i][j] = 0;
TaskDeviceValueNames[i][j] = 0;
TaskDeviceValueDecimals[i] = 0;
}
}
for (byte i = 0; i < PLUGIN_EXTRACONFIGVAR_MAX; ++i) {
TaskDevicePluginConfigLong[i] = 0;
TaskDevicePluginConfig[i] = 0;
}
}
byte TaskIndex;
char TaskDeviceName[41];
char TaskDeviceFormula[VARS_PER_TASK][41];
char TaskDeviceValueNames[VARS_PER_TASK][41];
long TaskDevicePluginConfigLong[PLUGIN_EXTRACONFIGVAR_MAX];
byte TaskDeviceValueDecimals[VARS_PER_TASK];
int16_t TaskDevicePluginConfig[PLUGIN_EXTRACONFIGVAR_MAX];
} ExtraTaskSettings;
struct EventStruct
{
EventStruct() :
Source(0), TaskIndex(0), ControllerIndex(0), ProtocolIndex(0), NotificationIndex(0),
BaseVarIndex(0), idx(0), sensorType(0), Par1(0), Par2(0), Par3(0), Par4(0), Par5(0),
OriginTaskIndex(0), Data(NULL) {}
byte Source;
byte TaskIndex; // index position in TaskSettings array, 0-11
byte ControllerIndex; // index position in Settings.Controller, 0-3
byte ProtocolIndex; // index position in protocol array, depending on which controller plugins are loaded.
byte NotificationIndex; // index position in Settings.Notification, 0-3
//Edwin: Not needed, and wasnt used. We can determine the protocol index with getNotificationProtocolIndex(NotificationIndex)
// byte NotificationProtocolIndex; // index position in notification array, depending on which controller plugins are loaded.
byte BaseVarIndex;
int idx;
byte sensorType;
int Par1;
int Par2;
int Par3;
int Par4;
int Par5;
byte OriginTaskIndex;
String String1;
String String2;
String String3;
byte *Data;
};
#define LOG_STRUCT_MESSAGE_SIZE 128
#define LOG_STRUCT_MESSAGE_LINES 20
struct LogStruct {
LogStruct() : write_idx(0), read_idx(0) {
for (int i = 0; i < LOG_STRUCT_MESSAGE_LINES; ++i) {
memset(Message[i], 0, LOG_STRUCT_MESSAGE_SIZE);
timeStamp[i] = 0;
}
}
void add(const char *line) {
write_idx = (write_idx + 1) % LOG_STRUCT_MESSAGE_LINES;
if (write_idx == read_idx) {
// Buffer full, move read_idx to overwrite oldest entry.
read_idx = (read_idx + 1) % LOG_STRUCT_MESSAGE_LINES;
}
timeStamp[write_idx] = millis();
strncpy(Message[write_idx], line, LOG_STRUCT_MESSAGE_SIZE-1);
}
// Read the next item and append it to the given string.
// Returns whether new lines are available.
bool get(String& output, const String& lineEnd) {
if (!isEmpty()) {
read_idx = (read_idx + 1) % LOG_STRUCT_MESSAGE_LINES;
output += formatLine(read_idx, lineEnd);
}
return !isEmpty();
}
bool get(String& output, const String& lineEnd, int line) {
int tmpread((write_idx + 1+line) % LOG_STRUCT_MESSAGE_LINES);
if (timeStamp[tmpread] != 0) {
output += formatLine(tmpread, lineEnd);
}
return !isEmpty();
}
bool getAll(String& output, const String& lineEnd) {
int tmpread((write_idx + 1) % LOG_STRUCT_MESSAGE_LINES);
bool someAdded = false;
while (tmpread != write_idx) {
if (timeStamp[tmpread] != 0) {
output += formatLine(tmpread, lineEnd);
someAdded = true;
}
tmpread = (tmpread + 1)% LOG_STRUCT_MESSAGE_LINES;
}
return someAdded;
}
bool isEmpty() {
return (write_idx == read_idx);
}
private:
String formatLine(int index, const String& lineEnd) {
String output;
output += timeStamp[index];
output += " : ";
output += Message[index];
output += lineEnd;
return output;
}
int write_idx;
int read_idx;
unsigned long timeStamp[LOG_STRUCT_MESSAGE_LINES];
char Message[LOG_STRUCT_MESSAGE_LINES][LOG_STRUCT_MESSAGE_SIZE];
} Logging;
struct DeviceStruct
{
DeviceStruct() :
Number(0), Type(0), VType(0), Ports(0),
PullUpOption(false), InverseLogicOption(false), FormulaOption(false),
ValueCount(0), Custom(false), SendDataOption(false), GlobalSyncOption(false),
TimerOption(false), TimerOptional(false), DecimalsOnly(false) {}
byte Number;
byte Type;
byte VType;
byte Ports;
boolean PullUpOption;
boolean InverseLogicOption;
boolean FormulaOption;
byte ValueCount;
boolean Custom;
boolean SendDataOption;
boolean GlobalSyncOption;
boolean TimerOption;
boolean TimerOptional;
boolean DecimalsOnly;
} Device[DEVICES_MAX + 1]; // 1 more because first device is empty device
struct ProtocolStruct
{
ProtocolStruct() :
Number(0), usesMQTT(false), usesAccount(false), usesPassword(false),
defaultPort(0), usesTemplate(false), usesID(false), Custom(false) {}
byte Number;
boolean usesMQTT;
boolean usesAccount;
boolean usesPassword;
int defaultPort;
boolean usesTemplate;
boolean usesID;
boolean Custom;
} Protocol[CPLUGIN_MAX];
struct NotificationStruct
{
NotificationStruct() :
Number(0), usesMessaging(false), usesGPIO(0) {}
byte Number;
boolean usesMessaging;
byte usesGPIO;
} Notification[NPLUGIN_MAX];
struct NodeStruct
{
NodeStruct() :
age(0), build(0), nodeName(NULL), nodeType(0)
{
for (byte i = 0; i < 4; ++i) ip[i] = 0;
}
byte ip[4];
byte age;
uint16_t build;
char* nodeName;
byte nodeType;
} Nodes[UNIT_MAX];
struct systemTimerStruct
{
systemTimerStruct() :
timer(0), plugin(0), Par1(0), Par2(0), Par3(0) {}
unsigned long timer;
byte plugin;
byte Par1;
byte Par2;
byte Par3;
} systemTimers[SYSTEM_TIMER_MAX];
struct systemCMDTimerStruct
{
systemCMDTimerStruct() : timer(0) {}
unsigned long timer;
String action;
} systemCMDTimers[SYSTEM_CMD_TIMER_MAX];
struct pinStatesStruct
{
byte plugin;
byte index;
byte mode;
uint16_t value;
} pinStates[PINSTATE_TABLE_MAX];
// this offsets are in blocks, bytes = blocks * 4
#define RTC_BASE_STRUCT 64
#define RTC_BASE_USERVAR 74
//max 40 bytes: ( 74 - 64 ) * 4
struct RTCStruct
{
byte ID1;
byte ID2;
boolean unused1;
byte factoryResetCounter;
byte deepSleepState;
byte unused2;
byte flashDayCounter;
unsigned long flashCounter;
unsigned long bootCounter;
} RTC;
int deviceCount = -1;
int protocolCount = -1;
int notificationCount = -1;
boolean printToWeb = false;
String printWebString = "";
boolean printToWebJSON = false;
float UserVar[VARS_PER_TASK * TASKS_MAX];
unsigned long RulesTimer[RULES_TIMER_MAX];
unsigned long timerSensor[TASKS_MAX];
unsigned long timer100ms;
unsigned long timer20ms;
unsigned long timer1s;
unsigned long timerwd;
unsigned long timermqtt;
unsigned long timermqtt_interval;
unsigned long lastSend;
unsigned long lastWeb;
unsigned int NC_Count = 0;
unsigned int C_Count = 0;
byte cmd_within_mainloop = 0;
unsigned long connectionFailures;
unsigned long wdcounter = 0;
unsigned long timerAPoff = 0;
unsigned long timerAwakeFromDeepSleep = 0;
#if FEATURE_ADC_VCC
float vcc = -1.0;
#endif
boolean WebLoggedIn = false;
int WebLoggedInTimer = 300;
boolean (*Plugin_ptr[PLUGIN_MAX])(byte, struct EventStruct*, String&);
byte Plugin_id[PLUGIN_MAX];
boolean (*CPlugin_ptr[CPLUGIN_MAX])(byte, struct EventStruct*, String&);
byte CPlugin_id[CPLUGIN_MAX];
boolean (*NPlugin_ptr[NPLUGIN_MAX])(byte, struct EventStruct*, String&);
byte NPlugin_id[NPLUGIN_MAX];
String dummyString = "";
byte lastBootCause = BOOT_CAUSE_MANUAL_REBOOT;
boolean wifiSetup = false;
boolean wifiSetupConnect = false;
uint8_t lastBSSID[6] = {0};
boolean wifiConnected = false;
unsigned long wifi_connect_timer = 0;
unsigned int wifi_connect_attempt = 0;
uint8_t lastWiFiSettings = 0;
unsigned long start = 0;
unsigned long elapsed = 0;
unsigned long loopCounter = 0;
unsigned long loopCounterLast = 0;
unsigned long loopCounterMax = 1;
unsigned long dailyResetCounter = 0;
String eventBuffer = "";
uint16_t lowestRAM = 0;
String lowestRAMfunction = "";
bool shouldReboot=false;
bool firstLoop=true;
boolean activeRuleSets[RULESETS_MAX];
#endif /* ESPEASY_GLOBALS_H_ */
+726 -107
View File
@@ -41,7 +41,7 @@
// Simple Arduino sketch for ESP module, supporting:
// =================================================================================
// Simple switch inputs and direct GPIO output control to drive relais, mosfets, etc
// Simple switch inputs and direct GPIO output control to drive relays, mosfets, etc
// Analog input (ESP-7/12 only)
// Pulse counters
// Dallas OneWire DS18b20 temperature sensors
@@ -71,27 +71,696 @@
// SHT1X temperature/humidity sensors
// Ser2Net server
#include "ESPEasy-Globals.h"
// ********************************************************************************
// User specific configuration
// ********************************************************************************
// Blynk_get prototype
boolean Blynk_get(const String& command, byte controllerIndex,float *data = NULL );
// Set default configuration settings if you want (not mandatory)
// You can always change these during runtime and save to eeprom
// After loading firmware, issue a 'reset' command to load the defaults.
int firstEnabledBlynkController() {
for (byte i = 0; i < CONTROLLER_MAX; ++i) {
byte ProtocolIndex = getProtocolIndex(Settings.Protocol[i]);
if (Protocol[ProtocolIndex].Number == 12 && Settings.ControllerEnabled[i]) {
return i;
}
#define DEFAULT_NAME "ESP_Easy" // Enter your device friendly name
#define DEFAULT_SSID "ssid" // Enter your network SSID
#define DEFAULT_KEY "wpakey" // Enter your network WPA key
#define DEFAULT_DELAY 60 // Enter your Send delay in seconds
#define DEFAULT_AP_KEY "configesp" // Enter network WPA key for AP (config) mode
#define DEFAULT_USE_STATIC_IP false // true or false enabled or disabled set static IP
#define DEFAULT_IP "192.168.0.50" // Enter your IP address
#define DEFAULT_DNS "192.168.0.1" // Enter your DNS
#define DEFAULT_GW "192.168.0.1" // Enter your gateway
#define DEFAULT_SUBNET "255.255.255.0" // Enter your subnet
#define DEFAULT_IPRANGE_LOW "0.0.0.0" // Allowed IP range to access webserver
#define DEFAULT_IPRANGE_HIGH "255.255.255.255" // Allowed IP range to access webserver
#define DEFAULT_IP_BLOCK_LEVEL 1 // 0: ALL_ALLOWED 1: LOCAL_SUBNET_ALLOWED 2: ONLY_IP_RANGE_ALLOWED
#define DEFAULT_CONTROLLER false // true or false enabled or disabled, set 1st controller defaults
// using a default template, you also need to set a DEFAULT PROTOCOL to a suitable MQTT protocol !
#define DEFAULT_PUB "sensors/espeasy/%sysname%/%tskname%/%valname%" // Enter your pub
#define DEFAULT_SUB "sensors/espeasy/%sysname%/#" // Enter your sub
#define DEFAULT_SERVER "192.168.0.8" // Enter your Server IP address
#define DEFAULT_PORT 8080 // Enter your Server port value
#define DEFAULT_PROTOCOL 1 // Protocol used for controller communications
// 1 = Domoticz HTTP
// 2 = Domoticz MQTT
// 3 = Nodo Telnet
// 4 = ThingSpeak
// 5 = OpenHAB MQTT
// 6 = PiDome MQTT
// 7 = EmonCMS
// 8 = Generic HTTP
// 9 = FHEM HTTP
#define UNIT 0
// Enable FEATURE_ADC_VCC to measure supply voltage using the analog pin
// Please note that the TOUT pin has to be disconnected in this mode
// Use the "System Info" device to read the VCC value
#define FEATURE_ADC_VCC false
#if defined(ESP8266)
//enable Arduino OTA updating.
//Note: This adds around 10kb to the firmware size, and 1kb extra ram.
// #define FEATURE_ARDUINO_OTA
//enable mDNS mode (adds about 6kb ram and some bytes IRAM)
// #define FEATURE_MDNS
#endif
#if defined(ESP32)
#define FEATURE_ARDUINO_OTA
//#define FEATURE_MDNS
#endif
//enable reporting status to ESPEasy developers.
//this informs us of crashes and stability issues.
// not finished yet!
// #define FEATURE_REPORTING
//Select which plugin sets you want to build.
//These are normally automaticly set via the Platformio build environment.
//If you use ArduinoIDE you might need to uncomment some of them, depending on your needs
//If you dont select any, a version with a minimal number of plugins will be biult for 512k versions.
//(512k is NOT finsihed or tested yet as of v2.0.0-dev6)
//build all the normal stable plugins (on by default)
#define PLUGIN_BUILD_NORMAL
//build all plugins that are in test stadium
//#define PLUGIN_BUILD_TESTING
//build all plugins that still are being developed and are broken or incomplete
//#define PLUGIN_BUILD_DEV
//add this if you want SD support (add 10k flash)
//#define FEATURE_SD
// ********************************************************************************
// DO NOT CHANGE ANYTHING BELOW THIS LINE
// ********************************************************************************
#define ESP_PROJECT_PID 2016110801L
#define VERSION 2 // config file version (not ESPEasy version). increase if you make incompatible changes to config system.
#define BUILD 20000 // git version 2.0.0
#if defined(ESP8266)
#define BUILD_NOTES " - Mega"
#endif
#if defined(ESP32)
#define BUILD_NOTES " - Mega32"
#endif
#ifndef BUILD_GIT
#define BUILD_GIT "(custom)"
#endif
#define MAX_FLASHWRITES_PER_DAY 100 // per 24 hour window
#define NODE_TYPE_ID_ESP_EASY_STD 1
#define NODE_TYPE_ID_ESP_EASYM_STD 17
#define NODE_TYPE_ID_ESP_EASY32_STD 33
#define NODE_TYPE_ID_ARDUINO_EASY_STD 65
#define NODE_TYPE_ID_NANO_EASY_STD 81
#define PLUGIN_INIT_ALL 1
#define PLUGIN_INIT 2
#define PLUGIN_READ 3
#define PLUGIN_ONCE_A_SECOND 4
#define PLUGIN_TEN_PER_SECOND 5
#define PLUGIN_DEVICE_ADD 6
#define PLUGIN_EVENTLIST_ADD 7
#define PLUGIN_WEBFORM_SAVE 8
#define PLUGIN_WEBFORM_LOAD 9
#define PLUGIN_WEBFORM_SHOW_VALUES 10
#define PLUGIN_GET_DEVICENAME 11
#define PLUGIN_GET_DEVICEVALUENAMES 12
#define PLUGIN_WRITE 13
#define PLUGIN_EVENT_OUT 14
#define PLUGIN_WEBFORM_SHOW_CONFIG 15
#define PLUGIN_SERIAL_IN 16
#define PLUGIN_UDP_IN 17
#define PLUGIN_CLOCK_IN 18
#define PLUGIN_TIMER_IN 19
#define PLUGIN_FIFTY_PER_SECOND 20
#define PLUGIN_SET_CONFIG 21
#define PLUGIN_GET_DEVICEGPIONAMES 22
#define PLUGIN_EXIT 23
#define PLUGIN_GET_CONFIG 24
#define CPLUGIN_PROTOCOL_ADD 1
#define CPLUGIN_PROTOCOL_TEMPLATE 2
#define CPLUGIN_PROTOCOL_SEND 3
#define CPLUGIN_PROTOCOL_RECV 4
#define CPLUGIN_GET_DEVICENAME 5
#define CPLUGIN_WEBFORM_SAVE 6
#define CPLUGIN_WEBFORM_LOAD 7
#define NPLUGIN_PROTOCOL_ADD 1
#define NPLUGIN_GET_DEVICENAME 2
#define NPLUGIN_WEBFORM_SAVE 3
#define NPLUGIN_WEBFORM_LOAD 4
#define NPLUGIN_WRITE 5
#define NPLUGIN_NOTIFY 6
#define NPLUGIN_NOT_FOUND 255
#define LOG_LEVEL_ERROR 1
#define LOG_LEVEL_INFO 2
#define LOG_LEVEL_DEBUG 3
#define LOG_LEVEL_DEBUG_MORE 4
#define LOG_LEVEL_DEBUG_DEV 9 // use for testing/debugging only, not for regular use
#define CMD_REBOOT 89
#define CMD_WIFI_DISCONNECT 135
#if defined(PLUGIN_BUILD_TESTING) || defined(PLUGIN_BUILD_DEV)
#define DEVICES_MAX 72
#else
#define DEVICES_MAX 64
#endif
#define TASKS_MAX 12 // max 12!
#define CONTROLLER_MAX 3 // max 4!
#define NOTIFICATION_MAX 3 // max 4!
#define VARS_PER_TASK 4
#define PLUGIN_MAX DEVICES_MAX
#define PLUGIN_CONFIGVAR_MAX 8
#define PLUGIN_CONFIGFLOATVAR_MAX 4
#define PLUGIN_CONFIGLONGVAR_MAX 4
#define PLUGIN_EXTRACONFIGVAR_MAX 16
#define CPLUGIN_MAX 16
#define NPLUGIN_MAX 4
#define UNIT_MAX 32 // Only relevant for UDP unicast message 'sweeps' and the nodelist.
#define RULES_TIMER_MAX 8
#define SYSTEM_TIMER_MAX 8
#define SYSTEM_CMD_TIMER_MAX 2
#define PINSTATE_TABLE_MAX 32
#define RULES_MAX_SIZE 2048
#define RULES_MAX_NESTING_LEVEL 3
#define RULESETS_MAX 4
#define PIN_MODE_UNDEFINED 0
#define PIN_MODE_INPUT 1
#define PIN_MODE_OUTPUT 2
#define PIN_MODE_PWM 3
#define PIN_MODE_SERVO 4
#define SEARCH_PIN_STATE true
#define NO_SEARCH_PIN_STATE false
#define DEVICE_TYPE_SINGLE 1 // connected through 1 datapin
#define DEVICE_TYPE_DUAL 2 // connected through 2 datapins
#define DEVICE_TYPE_TRIPLE 3 // connected through 3 datapins
#define DEVICE_TYPE_ANALOG 10 // AIN/tout pin
#define DEVICE_TYPE_I2C 20 // connected through I2C
#define DEVICE_TYPE_DUMMY 99 // Dummy device, has no physical connection
#define SENSOR_TYPE_SINGLE 1
#define SENSOR_TYPE_TEMP_HUM 2
#define SENSOR_TYPE_TEMP_BARO 3
#define SENSOR_TYPE_TEMP_HUM_BARO 4
#define SENSOR_TYPE_DUAL 5
#define SENSOR_TYPE_TRIPLE 6
#define SENSOR_TYPE_QUAD 7
#define SENSOR_TYPE_SWITCH 10
#define SENSOR_TYPE_DIMMER 11
#define SENSOR_TYPE_LONG 20
#define SENSOR_TYPE_WIND 21
#define VALUE_SOURCE_SYSTEM 1
#define VALUE_SOURCE_SERIAL 2
#define VALUE_SOURCE_HTTP 3
#define VALUE_SOURCE_MQTT 4
#define VALUE_SOURCE_UDP 5
#define BOOT_CAUSE_MANUAL_REBOOT 0
#define BOOT_CAUSE_COLD_BOOT 1
#define BOOT_CAUSE_DEEP_SLEEP 2
#define BOOT_CAUSE_EXT_WD 10
#define DAT_TASKS_SIZE 2048
#define DAT_TASKS_CUSTOM_OFFSET 1024
#define DAT_CUSTOM_CONTROLLER_SIZE 1024
#define DAT_CONTROLLER_SIZE 1024
#define DAT_NOTIFICATION_SIZE 1024
#define DAT_OFFSET_TASKS 4096 // each task = 2k, (1024 basic + 1024 bytes custom), 12 max
#define DAT_OFFSET_CONTROLLER 28672 // each controller = 1k, 4 max
#define DAT_OFFSET_CUSTOM_CONTROLLER 32768 // each custom controller config = 1k, 4 max.
#include "core_version.h"
#define FS_NO_GLOBALS
#if defined(ESP8266)
#define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASYM_STD
#define FILE_CONFIG "config.dat"
#define FILE_SECURITY "security.dat"
#define FILE_NOTIFICATION "notification.dat"
#define FILE_RULES "rules1.dat"
#include "lwip/tcp_impl.h"
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
ESP8266WebServer WebServer(80);
#include <DNSServer.h>
#include <Servo.h>
#include <ESP8266HTTPUpdateServer.h>
ESP8266HTTPUpdateServer httpUpdater(true);
#ifndef LWIP_OPEN_SRC
#define LWIP_OPEN_SRC
#endif
#include "lwip/opt.h"
#include "lwip/udp.h"
#include "lwip/igmp.h"
#include "include/UdpContext.h"
#include "limits.h"
extern "C" {
#include "user_interface.h"
}
return -1;
}
extern "C" {
#include "spi_flash.h"
}
extern "C" uint32_t _SPIFFS_start;
extern "C" uint32_t _SPIFFS_end;
extern "C" uint32_t _SPIFFS_page;
extern "C" uint32_t _SPIFFS_block;
#ifdef FEATURE_MDNS
#include <ESP8266mDNS.h>
#endif
#ifdef FEATURE_ARDUINO_OTA
#include <ArduinoOTA.h>
#include <ESP8266mDNS.h>
bool ArduinoOTAtriggered=false;
#endif
#define PIN_D_MAX 16
#endif
#if defined(ESP32)
#define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY32_STD
#define ICACHE_RAM_ATTR IRAM_ATTR
#define FILE_CONFIG "/config.dat"
#define FILE_SECURITY "/security.dat"
#define FILE_NOTIFICATION "/notification.dat"
#define FILE_RULES "/rules1.dat"
#include <WiFi.h>
#include <ESP32WebServer.h>
#include "SPIFFS.h"
ESP32WebServer WebServer(80);
#ifdef FEATURE_MDNS
#include <ESPmDNS.h>
#endif
#ifdef FEATURE_ARDUINO_OTA
#include <ArduinoOTA.h>
#include <ESPmDNS.h>
bool ArduinoOTAtriggered=false;
#endif
#define PIN_D_MAX 39
int8_t ledChannelPin[16];
#endif
#include <WiFiUdp.h>
#include <DNSServer.h>
#include <Wire.h>
#include <SPI.h>
#include <PubSubClient.h>
#include <FS.h>
#ifdef FEATURE_SD
#include <SD.h>
#else
using namespace fs;
#endif
#include <base64.h>
#if FEATURE_ADC_VCC
ADC_MODE(ADC_VCC);
#endif
// Setup DNS, only used if the ESP has no valid WiFi config
const byte DNS_PORT = 53;
IPAddress apIP(192, 168, 4, 1);
DNSServer dnsServer;
#ifdef FEATURE_MDNS
MDNSResponder mdns;
#endif
// MQTT client
WiFiClient mqtt;
PubSubClient MQTTclient(mqtt);
// udp protocol stuff (syslog, global sync, node info list, ntp time)
WiFiUDP portUDP;
struct SecurityStruct
{
char WifiSSID[32];
char WifiKey[64];
char WifiSSID2[32];
char WifiKey2[64];
char WifiAPKey[64];
char ControllerUser[CONTROLLER_MAX][26];
char ControllerPassword[CONTROLLER_MAX][64];
char Password[26];
byte AllowedIPrangeLow[4]; // TD-er: Use these
byte AllowedIPrangeHigh[4];
byte IPblockLevel;
//its safe to extend this struct, up to 4096 bytes, default values in config are 0
} SecuritySettings;
struct SettingsStruct
{
unsigned long PID;
int Version;
int16_t Build;
byte IP[4];
byte Gateway[4];
byte Subnet[4];
byte DNS[4];
byte IP_Octet;
byte Unit;
char Name[26];
char NTPHost[64];
unsigned long Delay;
int8_t Pin_i2c_sda;
int8_t Pin_i2c_scl;
int8_t Pin_status_led;
int8_t Pin_sd_cs;
int8_t PinBootStates[17];
byte Syslog_IP[4];
unsigned int UDPPort;
byte SyslogLevel;
byte SerialLogLevel;
byte WebLogLevel;
byte SDLogLevel;
unsigned long BaudRate;
unsigned long MessageDelay;
byte deepSleep;
boolean CustomCSS;
boolean DST;
byte WDI2CAddress;
boolean UseRules;
boolean UseSerial;
boolean UseSSDP;
boolean UseNTP;
unsigned long WireClockStretchLimit;
boolean GlobalSync;
unsigned long ConnectionFailuresThreshold;
int16_t TimeZone;
boolean MQTTRetainFlag;
boolean InitSPI;
byte Protocol[CONTROLLER_MAX];
byte Notification[NOTIFICATION_MAX]; //notifications, point to a NPLUGIN id
byte TaskDeviceNumber[TASKS_MAX];
unsigned int OLD_TaskDeviceID[TASKS_MAX];
union {
struct {
int8_t TaskDevicePin1[TASKS_MAX];
int8_t TaskDevicePin2[TASKS_MAX];
int8_t TaskDevicePin3[TASKS_MAX];
byte TaskDevicePort[TASKS_MAX];
};
int8_t TaskDevicePin[4][TASKS_MAX];
};
boolean TaskDevicePin1PullUp[TASKS_MAX];
int16_t TaskDevicePluginConfig[TASKS_MAX][PLUGIN_CONFIGVAR_MAX];
boolean TaskDevicePin1Inversed[TASKS_MAX];
float TaskDevicePluginConfigFloat[TASKS_MAX][PLUGIN_CONFIGFLOATVAR_MAX];
long TaskDevicePluginConfigLong[TASKS_MAX][PLUGIN_CONFIGLONGVAR_MAX];
boolean OLD_TaskDeviceSendData[TASKS_MAX];
boolean TaskDeviceGlobalSync[TASKS_MAX];
byte TaskDeviceDataFeed[TASKS_MAX];
unsigned long TaskDeviceTimer[TASKS_MAX];
boolean TaskDeviceEnabled[TASKS_MAX];
boolean ControllerEnabled[CONTROLLER_MAX];
boolean NotificationEnabled[NOTIFICATION_MAX];
unsigned int TaskDeviceID[CONTROLLER_MAX][TASKS_MAX];
boolean TaskDeviceSendData[CONTROLLER_MAX][TASKS_MAX];
boolean Pin_status_led_Inversed;
boolean deepSleepOnFail;
boolean UseValueLogger;
boolean ArduinoOTAEnable;
//its safe to extend this struct, up to several bytes, default values in config are 0
//look in misc.ino how config.dat is used because also other stuff is stored in it at different offsets.
//TODO: document config.dat somewhere here
} Settings;
struct ControllerSettingsStruct
{
boolean UseDNS;
byte IP[4];
unsigned int Port;
char HostName[65];
char Publish[129];
char Subscribe[129];
IPAddress getIP() const {
IPAddress host(IP[0], IP[1], IP[2], IP[3]);
return host;
}
String getHost() const {
if (UseDNS) {
return HostName;
}
return getIP().toString();
}
boolean connectToHost(WiFiClient &client) {
if (WiFi.status() != WL_CONNECTED) {
return false; // Not connected, so no use in wasting time to connect to a host.
}
if (UseDNS) {
return client.connect(HostName, Port);
}
return client.connect(getIP(), Port);
}
int beginPacket(WiFiUDP &client) {
if (WiFi.status() != WL_CONNECTED) {
return 0; // Not connected, so no use in wasting time to connect to a host.
}
if (UseDNS) {
return client.beginPacket(HostName, Port);
}
return client.beginPacket(getIP(), Port);
}
String getHostPortString() const {
String result = getHost();
result += ":";
result += Port;
return result;
}
};
struct NotificationSettingsStruct
{
char Server[65];
unsigned int Port;
char Domain[65];
char Sender[65];
char Receiver[65];
char Subject[129];
char Body[513];
byte Pin1;
byte Pin2;
//its safe to extend this struct, up to 4096 bytes, default values in config are 0
};
struct ExtraTaskSettingsStruct
{
byte TaskIndex;
char TaskDeviceName[41];
char TaskDeviceFormula[VARS_PER_TASK][41];
char TaskDeviceValueNames[VARS_PER_TASK][41];
long TaskDevicePluginConfigLong[PLUGIN_EXTRACONFIGVAR_MAX];
byte TaskDeviceValueDecimals[VARS_PER_TASK];
int16_t TaskDevicePluginConfig[PLUGIN_EXTRACONFIGVAR_MAX];
} ExtraTaskSettings;
struct EventStruct
{
byte Source;
byte TaskIndex; // index position in TaskSettings array, 0-11
byte ControllerIndex; // index position in Settings.Controller, 0-3
byte ProtocolIndex; // index position in protocol array, depending on which controller plugins are loaded.
byte NotificationIndex; // index position in Settings.Notification, 0-3
//Edwin: Not needed, and wasnt used. We can determine the protocol index with getNotificationProtocolIndex(NotificationIndex)
// byte NotificationProtocolIndex; // index position in notification array, depending on which controller plugins are loaded.
byte BaseVarIndex;
int idx;
byte sensorType;
int Par1;
int Par2;
int Par3;
int Par4;
int Par5;
byte OriginTaskIndex;
String String1;
String String2;
String String3;
byte *Data;
};
struct LogStruct
{
unsigned long timeStamp;
char* Message;
} Logging[10];
int logcount = -1;
struct DeviceStruct
{
byte Number;
byte Type;
byte VType;
byte Ports;
boolean PullUpOption;
boolean InverseLogicOption;
boolean FormulaOption;
byte ValueCount;
boolean Custom;
boolean SendDataOption;
boolean GlobalSyncOption;
boolean TimerOption;
boolean TimerOptional;
boolean DecimalsOnly;
} Device[DEVICES_MAX + 1]; // 1 more because first device is empty device
struct ProtocolStruct
{
byte Number;
boolean usesMQTT;
boolean usesAccount;
boolean usesPassword;
int defaultPort;
boolean usesTemplate;
boolean usesID;
} Protocol[CPLUGIN_MAX];
struct NotificationStruct
{
byte Number;
boolean usesMessaging;
byte usesGPIO;
} Notification[NPLUGIN_MAX];
struct NodeStruct
{
byte ip[4];
byte age;
uint16_t build;
char* nodeName;
byte nodeType;
} Nodes[UNIT_MAX];
struct systemTimerStruct
{
unsigned long timer;
byte plugin;
byte Par1;
byte Par2;
byte Par3;
} systemTimers[SYSTEM_TIMER_MAX];
struct systemCMDTimerStruct
{
unsigned long timer;
String action;
} systemCMDTimers[SYSTEM_CMD_TIMER_MAX];
struct pinStatesStruct
{
byte plugin;
byte index;
byte mode;
uint16_t value;
} pinStates[PINSTATE_TABLE_MAX];
// this offsets are in blocks, bytes = blocks * 4
#define RTC_BASE_STRUCT 64
#define RTC_BASE_USERVAR 74
//max 40 bytes: ( 74 - 64 ) * 4
struct RTCStruct
{
byte ID1;
byte ID2;
boolean unused1;
byte factoryResetCounter;
byte deepSleepState;
byte unused2;
byte flashDayCounter;
unsigned long flashCounter;
unsigned long bootCounter;
} RTC;
int deviceCount = -1;
int protocolCount = -1;
int notificationCount = -1;
boolean printToWeb = false;
String printWebString = "";
boolean printToWebJSON = false;
float UserVar[VARS_PER_TASK * TASKS_MAX];
unsigned long RulesTimer[RULES_TIMER_MAX];
unsigned long timerSensor[TASKS_MAX];
unsigned long timer100ms;
unsigned long timer20ms;
unsigned long timer1s;
unsigned long timerwd;
unsigned long lastSend;
unsigned long lastWeb;
unsigned int NC_Count = 0;
unsigned int C_Count = 0;
byte cmd_within_mainloop = 0;
unsigned long connectionFailures;
unsigned long wdcounter = 0;
unsigned long timerAPoff = 0;
#if FEATURE_ADC_VCC
float vcc = -1.0;
#endif
boolean WebLoggedIn = false;
int WebLoggedInTimer = 300;
boolean (*Plugin_ptr[PLUGIN_MAX])(byte, struct EventStruct*, String&);
byte Plugin_id[PLUGIN_MAX];
boolean (*CPlugin_ptr[CPLUGIN_MAX])(byte, struct EventStruct*, String&);
byte CPlugin_id[CPLUGIN_MAX];
boolean (*NPlugin_ptr[NPLUGIN_MAX])(byte, struct EventStruct*, String&);
byte NPlugin_id[NPLUGIN_MAX];
String dummyString = "";
byte lastBootCause = BOOT_CAUSE_MANUAL_REBOOT;
boolean wifiSetup = false;
boolean wifiSetupConnect = false;
unsigned long start = 0;
unsigned long elapsed = 0;
unsigned long loopCounter = 0;
unsigned long loopCounterLast = 0;
unsigned long loopCounterMax = 1;
unsigned long dailyResetCounter = 0;
String eventBuffer = "";
uint32_t lowestRAM = 0;
String lowestRAMfunction = "";
/*********************************************************************************************\
* SETUP
\*********************************************************************************************/
void setup()
{
#if defined(ESP32)
for(byte x = 0; x < 16; x++)
ledChannelPin[x] = -1;
#endif
lowestRAM = FreeMem();
@@ -148,13 +817,9 @@ void setup()
addLog(LOG_LEVEL_INFO, log);
fileSystemCheck();
LoadSettings();
checkRuleSets();
if (strcasecmp(SecuritySettings.WifiSSID, "ssid") == 0)
wifiSetup = true;
@@ -194,29 +859,6 @@ void setup()
hardwareInit();
//After booting, we want all the tasks to run without delaying more than neccesary.
//Plugins that need an initial startup delay need to overwrite their initial timerSensor value in PLUGIN_INIT
//They should also check if we returned from deep sleep so that they can skip the delay in that case.
for (byte x = 0; x < TASKS_MAX; x++)
if (Settings.TaskDeviceTimer[x] !=0)
timerSensor[x] = millis() + (x * Settings.MessageDelay);
timer100ms = 0; // timer for periodic actions 10 x per/sec
timer1s = 0; // timer for periodic actions once per/sec
timerwd = 0; // timer for watchdog once per 30 sec
timermqtt = 0; // Timer for the MQTT keep alive loop.
timermqtt_interval = 250; // Interval for checking MQTT
timerAwakeFromDeepSleep = millis();
PluginInit();
CPluginInit();
NPluginInit();
if (Settings.UseRules)
{
String event = F("System#Wake");
rulesProcessing(event);
}
WiFi.persistent(false); // Do not use SDK storage of SSID/WPA parameters
WifiAPconfig();
@@ -233,12 +875,28 @@ void setup()
}
}
else
WiFiConnectRelaxed();
// 3 connect attempts
WifiConnect(3);
#ifdef FEATURE_REPORTING
ReportStatus();
#endif
//After booting, we want all the tasks to run without delaying more than neccesary.
//Plugins that need an initial startup delay need to overwrite their initial timerSensor value in PLUGIN_INIT
//They should also check if we returned from deep sleep so that they can skip the delay in that case.
for (byte x = 0; x < TASKS_MAX; x++)
if (Settings.TaskDeviceTimer[x] !=0)
timerSensor[x] = millis() + (x * Settings.MessageDelay);
timer100ms = 0; // timer for periodic actions 10 x per/sec
timer1s = 0; // timer for periodic actions once per/sec
timerwd = 0; // timer for watchdog once per 30 sec
PluginInit();
CPluginInit();
NPluginInit();
WebServerInit();
#ifdef FEATURE_ARDUINO_OTA
@@ -249,6 +907,11 @@ void setup()
if (Settings.UDPPort != 0)
portUDP.begin(Settings.UDPPort);
// Setup MQTT Client
byte ProtocolIndex = getProtocolIndex(Settings.Protocol[0]);
if (Protocol[ProtocolIndex].usesMQTT && Settings.ControllerEnabled[0])
MQTTConnect();
sendSysInfoUDP(3);
if (Settings.UseNTP)
@@ -274,21 +937,6 @@ void setup()
}
int firstEnabledMQTTController() {
for (byte i = 0; i < CONTROLLER_MAX; ++i) {
byte ProtocolIndex = getProtocolIndex(Settings.Protocol[i]);
if (Protocol[ProtocolIndex].usesMQTT && Settings.ControllerEnabled[i]) {
return i;
}
}
return -1;
}
bool getControllerProtocolDisplayName(byte ProtocolIndex, byte parameterIdx, String& protoDisplayName) {
EventStruct tmpEvent;
tmpEvent.idx=parameterIdx;
return CPlugin_ptr[ProtocolIndex](CPLUGIN_GET_PROTOCOL_DISPLAY_NAME, &tmpEvent, protoDisplayName);
}
/*********************************************************************************************\
* MAIN LOOP
@@ -305,20 +953,14 @@ void loop()
}
// Deep sleep mode, just run all tasks one time and go back to sleep as fast as possible
if (firstLoop && isDeepSleepEnabled())
if (isDeepSleepEnabled())
{
// Setup MQTT Client
// Controller index is forced to the first enabled MQTT controller.
// This is normally done via frequent checks, but there's no time for in deepsleep.
int enabledMqttController = firstEnabledMQTTController();
if (enabledMqttController >= 0) {
MQTTConnect(enabledMqttController);
}
// Now run all frequent tasks
run50TimesPerSecond();
run10TimesPerSecond();
runEach30Seconds();
runOncePerSecond();
deepSleep(Settings.Delay);
//deepsleep will never return, its a special kind of reboot
}
//normal mode, run each task when its time
else
@@ -335,39 +977,9 @@ void loop()
if (timeOutReached(timer1s))
runOncePerSecond();
if (timeOutReached(timermqtt)) {
// MQTT_KEEPALIVE = 15 seconds.
timermqtt = millis() + timermqtt_interval;
//dont do this in backgroundtasks(), otherwise causes crashes. (https://github.com/letscontrolit/ESPEasy/issues/683)
int enabledMqttController = firstEnabledMQTTController();
if (enabledMqttController >= 0) {
if (!MQTTclient.loop()) {
if (!MQTTCheck(enabledMqttController)) {
// Check failed, no need to retry it immediately.
if (timermqtt_interval < 2000)
timermqtt_interval += 250;
} else {
timermqtt_interval = 250;
}
}
}
}
}
backgroundtasks();
if (readyForSleep()){
if (Settings.UseRules)
{
String event = F("System#Sleep");
rulesProcessing(event);
}
deepSleep(Settings.Delay);
//deepsleep will never return, its a special kind of reboot
}
firstLoop = false;
}
@@ -397,7 +1009,6 @@ void run10TimesPerSecond()
eventBuffer = "";
}
elapsed = micros() - start;
WebServer.handleClient();
}
@@ -435,13 +1046,17 @@ void runOncePerSecond()
}
case CMD_REBOOT:
{
ESP.reset();
#if defined(ESP8266)
ESP.reset();
#endif
#if defined(ESP32)
ESP.restart();
#endif
break;
}
}
cmd_within_mainloop = 0;
}
WifiCheck();
// clock events
if (Settings.UseNTP)
@@ -503,12 +1118,12 @@ void runEach30Seconds()
addLog(LOG_LEVEL_INFO, log);
sendSysInfoUDP(1);
refreshNodeList();
int enabledMqttController = firstEnabledMQTTController();
if (enabledMqttController >= 0) {
MQTTCheck(enabledMqttController);
}
if(Settings.ControllerEnabled[0])
MQTTCheck();
#if defined(ESP8266)
if (Settings.UseSSDP)
SSDP_update();
#endif
#if FEATURE_ADC_VCC
vcc = ESP.getVcc() / 1000.0;
#endif
@@ -517,6 +1132,8 @@ void runEach30Seconds()
if (loopCounterLast > loopCounterMax)
loopCounterMax = loopCounterLast;
WifiCheck();
#ifdef FEATURE_REPORTING
ReportStatus();
#endif
@@ -705,17 +1322,17 @@ void checkSystemTimers()
bool runningBackgroundTasks=false;
void backgroundtasks()
{
//always start with a yield
yield();
//prevent recursion!
if (runningBackgroundTasks)
{
yield();
return;
}
runningBackgroundTasks=true;
tcpCleanup();
#if defined(ESP8266)
tcpCleanup();
#endif
if (Settings.UseSerial)
if (Serial.available())
@@ -727,11 +1344,13 @@ void backgroundtasks()
dnsServer.processNextRequest();
WebServer.handleClient();
if(Settings.ControllerEnabled[0])
MQTTclient.loop();
checkUDP();
#ifdef FEATURE_ARDUINO_OTA
ArduinoOTA.handle();
if(Settings.ArduinoOTAEnable)
ArduinoOTA.handle();
//once OTA is triggered, only handle that and dont do other stuff. (otherwise it fails)
while (ArduinoOTAtriggered)
-69
View File
@@ -1,69 +0,0 @@
#ifndef ESPEASY_TIMETYPES_H_
#define ESPEASY_TIMETYPES_H_
#include <stdint.h>
struct timeStruct {
timeStruct() : Second(0), Minute(0), Hour(0), Wday(0), Day(0), Month(0), Year(0) {}
uint8_t Second;
uint8_t Minute;
uint8_t Hour;
uint8_t Wday; // day of week, sunday is day 1
uint8_t Day;
uint8_t Month;
uint8_t Year; // offset from 1970;
};
// convenient constants for TimeChangeRules
enum week_t {Last=0, First, Second, Third, Fourth};
enum dow_t {Sun=1, Mon, Tue, Wed, Thu, Fri, Sat};
enum month_t {Jan=1, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec};
// structure to describe rules for when daylight/summer time begins,
// or when standard time begins.
// For Daylight Saving Time Around the World, see:
// - https://www.timeanddate.com/time/dst/2018.html
// - https://en.wikipedia.org/wiki/Daylight_saving_time_by_country
struct TimeChangeRule {
TimeChangeRule() : week(0), dow(1), month(1), hour(0), offset(0) {}
TimeChangeRule(uint8_t weeknr, uint8_t downr, uint8_t m, uint8_t h, uint16_t minutesoffset) :
week(weeknr), dow(downr), month(m), hour(h), offset(minutesoffset) {}
// Construct time change rule from stored values optimized for minimum space.
TimeChangeRule(uint16_t flash_stored_value, int16_t minutesoffset) : offset(minutesoffset) {
hour = flash_stored_value & 0x001f;
month = (flash_stored_value >> 5) & 0x000f;
dow = (flash_stored_value >> 9) & 0x0007;
week = (flash_stored_value >> 12) & 0x0007;
}
uint16_t toFlashStoredValue() const {
uint16_t value = hour;
value = value | (month << 5);
value = value | (dow << 9);
value = value | (week << 12);
return value;
}
bool isValid() const {
return (week <= 4) && (dow != 0) && (dow <= 7) &&
(month != 0) && (month <= 12) && (hour <= 23) &&
(offset > -720) && (offset < 900); // UTC-12h ... UTC+14h + 1h DSToffset
}
uint8_t week; // First, Second, Third, Fourth, or Last week of the month
uint8_t dow; // day of week, 1=Sun, 2=Mon, ... 7=Sat
uint8_t month; // 1=Jan, 2=Feb, ... 12=Dec
uint8_t hour; // 0-23
int16_t offset; // offset from UTC in minutes
};
// Forward declartions
void applyTimeZone(uint32_t curTime = 0);
void setTimeZone(const TimeChangeRule& dstStart, const TimeChangeRule& stdStart, uint32_t curTime = 0);
uint32_t calcTimeChangeForRule(const TimeChangeRule& r, int yr);
String getTimeString(char delimiter, bool show_seconds=true);
String getTimeString_ampm(char delimiter, bool show_seconds=true);
#endif /* ESPEASY_TIMETYPES_H_ */
+9 -5
View File
@@ -1,5 +1,5 @@
/********************************************************************************************\
* Initialize specific hardware setings (only global ones, others are set through devices)
* Initialize specific hardware settings (only global ones, others are set through devices)
\*********************************************************************************************/
void hardwareInit()
@@ -37,7 +37,9 @@ void hardwareInit()
String log = F("INIT : I2C custom clockstretchlimit:");
log += Settings.WireClockStretchLimit;
addLog(LOG_LEVEL_INFO, log);
Wire.setClockStretchLimit(Settings.WireClockStretchLimit);
#if defined(ESP8266)
Wire.setClockStretchLimit(Settings.WireClockStretchLimit);
#endif
}
}
@@ -49,7 +51,7 @@ void hardwareInit()
Wire.write(0x83); // command to set pointer
Wire.write(17); // pointer value to status byte
Wire.endTransmission();
Wire.requestFrom(Settings.WDI2CAddress, (uint8_t)1);
if (Wire.available())
{
@@ -62,7 +64,7 @@ void hardwareInit()
}
}
}
// SPI Init
if (Settings.InitSPI)
{
@@ -77,7 +79,8 @@ void hardwareInit()
addLog(LOG_LEVEL_INFO, log);
}
if (Settings.Pin_sd_cs > 0)
#ifdef FEATURE_SD
if (Settings.Pin_sd_cs >= 0)
{
if (SD.begin(Settings.Pin_sd_cs))
{
@@ -90,6 +93,7 @@ void hardwareInit()
addLog(LOG_LEVEL_ERROR, log);
}
}
#endif
}
+1200 -628
View File
File diff suppressed because it is too large Load Diff
+190 -69
View File
@@ -14,32 +14,58 @@ void syslog(const char *message)
portUDP.beginPacket(broadcastIP, 514);
char str[256];
str[0] = 0;
// An RFC3164 compliant message must be formated like : "<PRIO>[TimeStamp ]Hostname TaskName: Message"
// Using Settings.Name as the Hostname (Hostname must NOT content space)
snprintf_P(str, sizeof(str), PSTR("<7>%s EspEasy: %s"), Settings.Name, message);
// Using Setting.Unit to build a Hostname
//snprintf_P(str, sizeof(str), PSTR("<7>EspEasy_%u ESP: %s"), Settings.Unit, message);
snprintf_P(str, sizeof(str), PSTR("<7>ESP Unit: %u : %s"), Settings.Unit, message);
#if defined(ESP8266)
portUDP.write(str);
#endif
#if defined(ESP32)
portUDP.write((uint8_t*)str,strlen(str));
#endif
portUDP.endPacket();
}
}
/*********************************************************************************************\
Structs for UDP messaging
\*********************************************************************************************/
struct infoStruct
{
byte header = 255;
byte ID = 3;
byte sourcelUnit;
byte destUnit;
byte sourceTaskIndex;
byte destTaskIndex;
byte deviceNumber;
char taskName[26];
char ValueNames[VARS_PER_TASK][26];
};
struct dataStruct
{
byte header = 255;
byte ID = 5;
byte sourcelUnit;
byte destUnit;
byte sourceTaskIndex;
byte destTaskIndex;
float Values[VARS_PER_TASK];
};
//TODO: add sysinfoStruct
/*********************************************************************************************\
Check UDP messages (ESPEasy propiertary protocol)
\*********************************************************************************************/
boolean runningUPDCheck = false;
void checkUDP()
{
if (Settings.UDPPort == 0)
return;
if (runningUPDCheck)
return;
runningUPDCheck = true;
// UDP events
int packetSize = portUDP.parsePacket();
if (packetSize)
@@ -50,6 +76,7 @@ void checkUDP()
if (portUDP.remotePort() == 123)
{
// unexpected NTP reply, drop for now...
runningUPDCheck = false;
return;
}
char packetBuffer[128];
@@ -68,10 +95,22 @@ void checkUDP()
}
else
{
if (packetBuffer[1] > 1 && packetBuffer[1] < 6)
{
String log = (F("UDP : Sensor msg "));
for (byte x = 1; x < 6; x++)
{
log += " ";
log += (int)packetBuffer[x];
}
addLog(LOG_LEVEL_DEBUG_MORE, log);
}
// binary data!
switch (packetBuffer[1])
{
//TODO: use a nice struct for it
case 1: // sysinfo message
{
byte mac[6];
@@ -99,27 +138,155 @@ void checkUDP()
}
char macaddress[20];
sprintf_P(macaddress, PSTR("%02x:%02x:%02x:%02x:%02x:%02x"), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
char ipaddress[16];
sprintf_P(ipaddress, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]);
formatMAC(mac, macaddress);
char ipaddress[20];
formatIP(ip, ipaddress);
char log[80];
sprintf_P(log, PSTR("UDP : %s,%s,%u"), macaddress, ipaddress, unit);
addLog(LOG_LEVEL_DEBUG_MORE, log);
break;
}
case 2: // sensor info pull request
{
SendUDPTaskInfo(packetBuffer[2], packetBuffer[5], packetBuffer[4]);
break;
}
case 3: // sensor info
{
if (Settings.GlobalSync)
{
struct infoStruct infoReply;
memcpy((byte*)&infoReply, (byte*)&packetBuffer, sizeof(infoStruct));
// to prevent flash wear out (bugs in communication?) we can only write to an empty task
// so it will write only once and has to be cleared manually through webgui
if (Settings.TaskDeviceNumber[infoReply.destTaskIndex] == 0)
{
Settings.TaskDeviceNumber[infoReply.destTaskIndex] = infoReply.deviceNumber;
Settings.TaskDeviceDataFeed[infoReply.destTaskIndex] = 1; // remote feed
for (byte x=0; x < CONTROLLER_MAX; x++)
Settings.TaskDeviceSendData[x][infoReply.destTaskIndex] = false;
strcpy(ExtraTaskSettings.TaskDeviceName, infoReply.taskName);
for (byte x = 0; x < VARS_PER_TASK; x++)
strcpy( ExtraTaskSettings.TaskDeviceValueNames[x], infoReply.ValueNames[x]);
SaveTaskSettings(infoReply.destTaskIndex);
SaveSettings();
}
}
break;
}
case 4: // sensor data pull request
{
SendUDPTaskData(packetBuffer[2], packetBuffer[5], packetBuffer[4]);
break;
}
case 5: // sensor data
{
if (Settings.GlobalSync)
{
struct dataStruct dataReply;
memcpy((byte*)&dataReply, (byte*)&packetBuffer, sizeof(dataStruct));
// only if this task has a remote feed, update values
if (Settings.TaskDeviceDataFeed[dataReply.destTaskIndex] != 0)
{
for (byte x = 0; x < VARS_PER_TASK; x++)
{
UserVar[dataReply.destTaskIndex * VARS_PER_TASK + x] = dataReply.Values[x];
}
if (Settings.UseRules)
createRuleEvents(dataReply.destTaskIndex);
}
}
break;
}
default:
{
struct EventStruct TempEvent;
TempEvent.Data = (byte*)packetBuffer;
TempEvent.Par1 = remoteIP[3];
PluginCall(PLUGIN_UDP_IN, &TempEvent, dummyString);
CPluginCall(CPLUGIN_UDP_IN, &TempEvent);
break;
}
}
}
}
#if defined(ESP32) // testing
portUDP.flush();
#endif
runningUPDCheck = false;
}
/*********************************************************************************************\
Send task info using UDP message
\*********************************************************************************************/
void SendUDPTaskInfo(byte destUnit, byte sourceTaskIndex, byte destTaskIndex)
{
if (WiFi.status() != WL_CONNECTED) {
return;
}
struct infoStruct infoReply;
infoReply.sourcelUnit = Settings.Unit;
infoReply.sourceTaskIndex = sourceTaskIndex;
infoReply.destTaskIndex = destTaskIndex;
LoadTaskSettings(infoReply.sourceTaskIndex);
infoReply.deviceNumber = Settings.TaskDeviceNumber[infoReply.sourceTaskIndex];
strcpy(infoReply.taskName, ExtraTaskSettings.TaskDeviceName);
for (byte x = 0; x < VARS_PER_TASK; x++)
strcpy(infoReply.ValueNames[x], ExtraTaskSettings.TaskDeviceValueNames[x]);
byte firstUnit = 1;
byte lastUnit = UNIT_MAX - 1;
if (destUnit != 0)
{
firstUnit = destUnit;
lastUnit = destUnit;
}
for (byte x = firstUnit; x <= lastUnit; x++)
{
infoReply.destUnit = x;
sendUDP(x, (byte*)&infoReply, sizeof(infoStruct));
delay(10);
}
delay(50);
}
/*********************************************************************************************\
Send task data using UDP message
\*********************************************************************************************/
void SendUDPTaskData(byte destUnit, byte sourceTaskIndex, byte destTaskIndex)
{
if (WiFi.status() != WL_CONNECTED) {
return;
}
struct dataStruct dataReply;
dataReply.sourcelUnit = Settings.Unit;
dataReply.sourceTaskIndex = sourceTaskIndex;
dataReply.destTaskIndex = destTaskIndex;
for (byte x = 0; x < VARS_PER_TASK; x++)
dataReply.Values[x] = UserVar[dataReply.sourceTaskIndex * VARS_PER_TASK + x];
byte firstUnit = 1;
byte lastUnit = UNIT_MAX - 1;
if (destUnit != 0)
{
firstUnit = destUnit;
lastUnit = destUnit;
}
for (byte x = firstUnit; x <= lastUnit; x++)
{
dataReply.destUnit = x;
sendUDP(x, (byte*) &dataReply, sizeof(dataStruct));
delay(10);
}
delay(50);
}
@@ -128,7 +295,7 @@ void checkUDP()
\*********************************************************************************************/
void SendUDPCommand(byte destUnit, char* data, byte dataLength)
{
if (!WiFiConnected(100)) {
if (WiFi.status() != WL_CONNECTED) {
return;
}
byte firstUnit = 1;
@@ -152,7 +319,7 @@ void SendUDPCommand(byte destUnit, char* data, byte dataLength)
\*********************************************************************************************/
void sendUDP(byte unit, byte* data, byte size)
{
if (!WiFiConnected(100)) {
if (WiFi.status() != WL_CONNECTED) {
return;
}
if (unit != 255)
@@ -198,7 +365,7 @@ void refreshNodeList()
void sendSysInfoUDP(byte repeats)
{
char log[80];
if (Settings.UDPPort == 0 || !WiFiConnected(100))
if (Settings.UDPPort == 0 || WiFi.status() != WL_CONNECTED)
return;
// TODO: make a nice struct of it and clean up
@@ -253,19 +420,17 @@ void sendSysInfoUDP(byte repeats)
}
}
#if defined(ESP8266)
/********************************************************************************************\
Respond to HTTP XML requests for SSDP information
\*********************************************************************************************/
void SSDP_schema(WiFiClient &client) {
if (!WiFiConnected(100)) {
if (WiFi.status() != WL_CONNECTED) {
return;
}
IPAddress ip = WiFi.localIP();
char str[20];
sprintf_P(str, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]);
uint32_t chipId = ESP.getChipId();
const IPAddress ip = WiFi.localIP();
const uint32_t chipId = ESP.getChipId();
char uuid[64];
sprintf_P(uuid, PSTR("38323636-4558-4dda-9188-cda0e6%02x%02x%02x"),
(uint16_t) ((chipId >> 16) & 0xff),
@@ -285,7 +450,7 @@ void SSDP_schema(WiFiClient &client) {
"<minor>0</minor>"
"</specVersion>"
"<URLBase>http://");
ssdp_schema += str;
ssdp_schema += formatIP(ip);
ssdp_schema += F(":80/</URLBase>"
"<device>"
"<deviceType>urn:schemas-upnp-org:device:BinaryLight:1</deviceType>"
@@ -572,50 +737,6 @@ void SSDP_update() {
while (_server->next())
_server->flush();
}
}
// Check WiFi connection. Maximum timeout 500 msec.
bool WiFiConnected(uint32_t timeout_ms) {
uint32_t timer = millis() + (timeout_ms > 500 ? 500 : timeout_ms);
uint32_t min_delay = timeout_ms / 20;
if (min_delay < 10) {
yield(); // Allow at least once time for backgroundtasks
min_delay = 10;
}
if (!wifiConnected) {
// Apparently something needs network, perform check to see if it is ready now.
if (tryConnectWiFi())
checkWifiJustConnected();
}
while (WiFi.status() != WL_CONNECTED) {
if (timeOutReached(timer)) {
return false;
}
delay(min_delay); // Allow the backgroundtasks to continue procesing.
}
return true;
}
bool hostReachable(const IPAddress& ip) {
// Only do 1 ping at a time to return early
byte retry = 3;
while (retry > 0) {
if (Ping.ping(ip, 1)) return true;
delay(50);
--retry;
}
String log = F("Host unreachable: ");
log += ip;
addLog(LOG_LEVEL_ERROR, log);
return false;
}
bool hostReachable(const String& hostname) {
IPAddress remote_addr;
if (WiFi.hostByName(hostname.c_str(), remote_addr))
return hostReachable(remote_addr);
String log = F("Hostname cannot be resolved: ");
log += hostname;
addLog(LOG_LEVEL_ERROR, log);
return false;
}
#endif
+51
View File
@@ -0,0 +1,51 @@
#define WiFi_Logo_width 60
#define WiFi_Logo_height 36
const char WiFi_Logo_bits[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF,
0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0x03, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0xFF, 0x07, 0xC0, 0x83, 0x01, 0x80, 0xFF, 0xFF, 0xFF,
0x01, 0x00, 0x07, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0C, 0x00,
0xC0, 0xFF, 0xFF, 0x7C, 0x00, 0x60, 0x0C, 0x00, 0xC0, 0x31, 0x46, 0x7C,
0xFC, 0x77, 0x08, 0x00, 0xE0, 0x23, 0xC6, 0x3C, 0xFC, 0x67, 0x18, 0x00,
0xE0, 0x23, 0xE4, 0x3F, 0x1C, 0x00, 0x18, 0x00, 0xE0, 0x23, 0x60, 0x3C,
0x1C, 0x70, 0x18, 0x00, 0xE0, 0x03, 0x60, 0x3C, 0x1C, 0x70, 0x18, 0x00,
0xE0, 0x07, 0x60, 0x3C, 0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, 0x70, 0x3C,
0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00,
0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00, 0xE0, 0x8F, 0x71, 0x3C,
0x1C, 0x70, 0x18, 0x00, 0xC0, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x08, 0x00,
0xC0, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x0C, 0x00, 0x80, 0xFF, 0xFF, 0x1F,
0x00, 0x00, 0x06, 0x00, 0x80, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x07, 0x00,
0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xF8, 0xFF, 0xFF,
0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00,
0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF,
0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
const char activeSymbole[] PROGMEM = {
B00000000,
B00000000,
B00011000,
B00100100,
B01000010,
B01000010,
B00100100,
B00011000
};
const char inactiveSymbole[] PROGMEM = {
B00000000,
B00000000,
B00000000,
B00000000,
B00011000,
B00011000,
B00000000,
B00000000
};
+51
View File
@@ -0,0 +1,51 @@
#define WiFi_Logo_width 60
#define WiFi_Logo_height 36
const char WiFi_Logo_bits[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF,
0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0x03, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0xFF, 0x07, 0xC0, 0x83, 0x01, 0x80, 0xFF, 0xFF, 0xFF,
0x01, 0x00, 0x07, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0C, 0x00,
0xC0, 0xFF, 0xFF, 0x7C, 0x00, 0x60, 0x0C, 0x00, 0xC0, 0x31, 0x46, 0x7C,
0xFC, 0x77, 0x08, 0x00, 0xE0, 0x23, 0xC6, 0x3C, 0xFC, 0x67, 0x18, 0x00,
0xE0, 0x23, 0xE4, 0x3F, 0x1C, 0x00, 0x18, 0x00, 0xE0, 0x23, 0x60, 0x3C,
0x1C, 0x70, 0x18, 0x00, 0xE0, 0x03, 0x60, 0x3C, 0x1C, 0x70, 0x18, 0x00,
0xE0, 0x07, 0x60, 0x3C, 0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, 0x70, 0x3C,
0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00,
0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00, 0xE0, 0x8F, 0x71, 0x3C,
0x1C, 0x70, 0x18, 0x00, 0xC0, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x08, 0x00,
0xC0, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x0C, 0x00, 0x80, 0xFF, 0xFF, 0x1F,
0x00, 0x00, 0x06, 0x00, 0x80, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x07, 0x00,
0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xF8, 0xFF, 0xFF,
0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00,
0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF,
0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
const char activeSymbole[] PROGMEM = {
B00000000,
B00000000,
B00011000,
B00100100,
B01000010,
B01000010,
B00100100,
B00011000
};
const char inactiveSymbole[] PROGMEM = {
B00000000,
B00000000,
B00000000,
B00000000,
B00011000,
B00011000,
B00000000,
B00000000
};
-383
View File
@@ -1,383 +0,0 @@
/********************************************************************************************\
Convert a char string to integer
\*********************************************************************************************/
//FIXME: change original code so it uses String and String.toInt()
unsigned long str2int(char *string)
{
unsigned long temp = atof(string);
return temp;
}
/********************************************************************************************\
Check if valid float and convert string to float.
\*********************************************************************************************/
bool string2float(const String& string, float& floatvalue) {
if (!isFloat(string)) return false;
floatvalue = atof(string.c_str());
return true;
}
/********************************************************************************************\
Convert a char string to IP byte array
\*********************************************************************************************/
boolean str2ip(const String& string, byte* IP) {
return str2ip(string.c_str(), IP);
}
boolean str2ip(const char *string, byte* IP)
{
IPAddress tmpip; // Default constructor => set to 0.0.0.0
if (*string == 0 || tmpip.fromString(string)) {
// Eiher empty string or a valid IP addres, so copy value.
for (byte i = 0; i < 4; ++i)
IP[i] = tmpip[i];
return true;
}
return false;
}
// Call this by first declaring a char array of size 20, like:
// char strIP[20];
// formatIP(ip, strIP);
void formatIP(const IPAddress& ip, char (&strIP)[20]) {
sprintf_P(strIP, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]);
}
String formatIP(const IPAddress& ip) {
char strIP[20];
formatIP(ip, strIP);
return String(strIP);
}
void formatMAC(const uint8_t* mac, char (&strMAC)[20]) {
sprintf_P(strMAC, PSTR("%02X:%02X:%02X:%02X:%02X:%02X"), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
/*********************************************************************************************\
Workaround for removing trailing white space when String() converts a float with 0 decimals
\*********************************************************************************************/
String toString(float value, byte decimals)
{
String sValue = String(value, decimals);
sValue.trim();
return sValue;
}
/*********************************************************************************************\
Format a value to the set number of decimals
\*********************************************************************************************/
String formatUserVar(struct EventStruct *event, byte rel_index)
{
float f(UserVar[event->BaseVarIndex + rel_index]);
if (!isValidFloat(f)) {
String log = F("Invalid float value for TaskIndex: ");
log += event->TaskIndex;
log += F(" varnumber: ");
log += rel_index;
addLog(LOG_LEVEL_DEBUG, log);
f = 0;
}
return toString(f, ExtraTaskSettings.TaskDeviceValueDecimals[rel_index]);
}
/*********************************************************************************************\
Wrap a string with given pre- and postfix string.
\*********************************************************************************************/
String wrap_String(const String& string, const String& wrap) {
String result;
result.reserve(string.length() + 2* wrap.length());
result = wrap;
result += string;
result += wrap;
return result;
}
/*********************************************************************************************\
Format an object value pair for use in JSON.
\*********************************************************************************************/
String to_json_object_value(const String& object, const String& value) {
String result;
result.reserve(object.length() + value.length() + 6);
result = wrap_String(object, F("\""));
result += F(":");
if (value.length() == 0 || !isFloat(value)) {
result += wrap_String(value, F("\""));
} else {
result += value;
}
return result;
}
/*********************************************************************************************\
Parse a string and get the xth command or parameter
\*********************************************************************************************/
String parseString(String& string, byte indexFind)
{
String tmpString = string;
tmpString += ",";
tmpString.replace(" ", ",");
String locateString = "";
byte count = 0;
int index = tmpString.indexOf(',');
while (index > 0)
{
count++;
locateString = tmpString.substring(0, index);
tmpString = tmpString.substring(index + 1);
index = tmpString.indexOf(',');
if (count == indexFind)
{
locateString.toLowerCase();
return locateString;
}
}
return "";
}
/*********************************************************************************************\
Parse a string and get the xth command or parameter
\*********************************************************************************************/
int getParamStartPos(String& string, byte indexFind)
{
String tmpString = string;
byte count = 0;
tmpString.replace(" ", ",");
for (unsigned int x = 0; x < tmpString.length(); x++)
{
if (tmpString.charAt(x) == ',')
{
count++;
if (count == (indexFind - 1))
return x + 1;
}
}
return -1;
}
//escapes special characters in strings for use in html-forms
void htmlEscape(String & html)
{
html.replace("&", "&amp;");
html.replace("\"", "&quot;");
html.replace("'", "&#039;");
html.replace("<", "&lt;");
html.replace(">", "&gt;");
}
/********************************************************************************************\
replace other system variables like %sysname%, %systime%, %ip%
\*********************************************************************************************/
void parseControllerVariables(String& s, struct EventStruct *event, boolean useURLencode) {
parseSystemVariables(s, useURLencode);
parseEventVariables(s, event, useURLencode);
parseStandardConversions(s, useURLencode);
}
void repl(const String& key, const String& val, String& s, boolean useURLencode)
{
if (useURLencode) {
s.replace(key, URLEncode(val.c_str()));
} else {
s.replace(key, val);
}
}
void parseSpecialCharacters(String& s, boolean useURLencode)
{
bool no_accolades = s.indexOf('{') == -1 || s.indexOf('}') == -1;
bool no_html_entity = s.indexOf('&') == -1 || s.indexOf(';') == -1;
if (no_accolades && no_html_entity)
return; // Nothing to replace
{
// Degree
const char degree[3] = {0xc2, 0xb0, 0}; // Unicode degree symbol
const char degreeC[4] = {0xe2, 0x84, 0x83, 0}; // Unicode degreeC symbol
const char degree_C[4] = {0xc2, 0xb0, 'C', 0}; // Unicode degree symbol + captial C
repl(F("{D}"), degree, s, useURLencode);
repl(F("&deg;"), degree, s, useURLencode);
repl(degreeC, degree_C, s, useURLencode);
}
{
// Angle quotes
const char laquo[3] = {0xc2, 0xab, 0}; // Unicode left angle quotes symbol
const char raquo[3] = {0xc2, 0xbb, 0}; // Unicode right angle quotes symbol
repl(F("{<<}"), laquo, s, useURLencode);
repl(F("&laquo;"), laquo, s, useURLencode);
repl(F("{>>}"), raquo, s, useURLencode);
repl(F("&raquo;"), raquo, s, useURLencode);
}
{
// Greek letter Mu
const char mu[3] = {0xc2, 0xb5, 0}; // Unicode greek letter mu
repl(F("{u}"), mu, s, useURLencode);
repl(F("&micro;"), mu, s, useURLencode);
}
{
// Currency
const char euro[4] = {0xe2, 0x82, 0xac, 0}; // Unicode euro symbol
const char yen[3] = {0xc2, 0xa5, 0}; // Unicode yen symbol
const char pound[3] = {0xc2, 0xa3, 0}; // Unicode pound symbol
const char cent[3] = {0xc2, 0xa2, 0}; // Unicode cent symbol
repl(F("{E}"), euro, s, useURLencode);
repl(F("&euro;"), euro, s, useURLencode);
repl(F("{Y}"), yen, s, useURLencode);
repl(F("&yen;"), yen, s, useURLencode);
repl(F("{P}"), pound, s, useURLencode);
repl(F("&pound;"), pound, s, useURLencode);
repl(F("{c}"), cent, s, useURLencode);
repl(F("&cent;"), cent, s, useURLencode);
}
{
// Math symbols
const char sup1[3] = {0xc2, 0xb9, 0}; // Unicode sup1 symbol
const char sup2[3] = {0xc2, 0xb2, 0}; // Unicode sup2 symbol
const char sup3[3] = {0xc2, 0xb3, 0}; // Unicode sup3 symbol
const char frac14[3] = {0xc2, 0xbc, 0}; // Unicode frac14 symbol
const char frac12[3] = {0xc2, 0xbd, 0}; // Unicode frac12 symbol
const char frac34[3] = {0xc2, 0xbe, 0}; // Unicode frac34 symbol
const char plusmn[3] = {0xc2, 0xb1, 0}; // Unicode plusmn symbol
const char times[3] = {0xc3, 0x97, 0}; // Unicode times symbol
const char divide[3] = {0xc3, 0xb7, 0}; // Unicode divide symbol
repl(F("{^1}"), sup1, s, useURLencode);
repl(F("&sup1;"), sup1, s, useURLencode);
repl(F("{^2}"), sup2, s, useURLencode);
repl(F("&sup2;"), sup2, s, useURLencode);
repl(F("{^3}"), sup3, s, useURLencode);
repl(F("&sup3;"), sup3, s, useURLencode);
repl(F("{1_4}"), frac14, s, useURLencode);
repl(F("&frac14;"), frac14, s, useURLencode);
repl(F("{1_2}"), frac12, s, useURLencode);
repl(F("&frac12;"), frac12, s, useURLencode);
repl(F("{3_4}"), frac34, s, useURLencode);
repl(F("&frac34;"), frac34, s, useURLencode);
repl(F("{+-}"), plusmn, s, useURLencode);
repl(F("&plusmn;"), plusmn, s, useURLencode);
repl(F("{x}"), times, s, useURLencode);
repl(F("&times;"), times, s, useURLencode);
repl(F("{..}"), divide, s, useURLencode);
repl(F("&divide;"), divide, s, useURLencode);
}
}
// Simple macro to create the replacement string only when needed.
#define SMART_REPL(T,S) if (s.indexOf(T) != -1) { repl((T), (S), s, useURLencode);}
void parseSystemVariables(String& s, boolean useURLencode)
{
parseSpecialCharacters(s, useURLencode);
if (s.indexOf('%') == -1)
return; // Nothing to replace
#if FEATURE_ADC_VCC
repl(F("%vcc%"), String(vcc), s, useURLencode);
#endif
repl(F("%CR%"), F("\r"), s, useURLencode);
repl(F("%LF%"), F("\n"), s, useURLencode);
SMART_REPL(F("%ip%"),WiFi.localIP().toString())
SMART_REPL(F("%rssi%"), String((WiFi.status() == WL_CONNECTED) ? WiFi.RSSI() : 0))
SMART_REPL(F("%ssid%"), (WiFi.status() == WL_CONNECTED) ? WiFi.SSID() : F("--"))
SMART_REPL(F("%unit%"), String(Settings.Unit))
SMART_REPL(F("%mac%"), String(WiFi.macAddress()))
#if defined(ESP8266)
SMART_REPL(F("%mac_int%"), String(ESP.getChipId())) // Last 24 bit of MAC address as integer, to be used in rules.
#endif
if (s.indexOf(F("%sys")) != -1) {
SMART_REPL(F("%sysload%"), String(100 - (100 * loopCounterLast / loopCounterMax)))
SMART_REPL(F("%systm_hm%"), getTimeString(':', false))
SMART_REPL(F("%systm_hm_am%"), getTimeString_ampm(':', false))
SMART_REPL(F("%systime%"), getTimeString(':'))
SMART_REPL(F("%systime_am%"), getTimeString_ampm(':'))
repl(F("%sysname%"), Settings.Name, s, useURLencode);
// valueString is being used by the macro.
char valueString[5];
#define SMART_REPL_TIME(T,F,V) if (s.indexOf(T) != -1) { sprintf_P(valueString, (F), (V)); repl((T),valueString, s, useURLencode);}
SMART_REPL_TIME(F("%syshour%"), PSTR("%02d"), hour())
SMART_REPL_TIME(F("%sysmin%"), PSTR("%02d"), minute())
SMART_REPL_TIME(F("%syssec%"),PSTR("%02d"), second())
SMART_REPL_TIME(F("%sysday%"), PSTR("%02d"), day())
SMART_REPL_TIME(F("%sysmonth%"),PSTR("%02d"), month())
SMART_REPL_TIME(F("%sysyear%"), PSTR("%04d"), year())
SMART_REPL_TIME(F("%sysyears%"),PSTR("%02d"), year()%100)
SMART_REPL(F("%sysweekday%"), String(weekday()))
SMART_REPL(F("%sysweekday_s%"), weekday_str())
#undef SMART_REPL_TIME
}
SMART_REPL(F("%lcltime%"), getDateTimeString('-',':',' '))
SMART_REPL(F("%lcltime_am%"), getDateTimeString_ampm('-',':',' '))
SMART_REPL(F("%uptime%"), String(wdcounter / 2))
repl(F("%tskname%"), ExtraTaskSettings.TaskDeviceName, s, useURLencode);
if (s.indexOf("%vname") != -1) {
repl(F("%vname1%"), ExtraTaskSettings.TaskDeviceValueNames[0], s, useURLencode);
repl(F("%vname2%"), ExtraTaskSettings.TaskDeviceValueNames[1], s, useURLencode);
repl(F("%vname3%"), ExtraTaskSettings.TaskDeviceValueNames[2], s, useURLencode);
repl(F("%vname4%"), ExtraTaskSettings.TaskDeviceValueNames[3], s, useURLencode);
}
}
void parseEventVariables(String& s, struct EventStruct *event, boolean useURLencode)
{
SMART_REPL(F("%id%"), String(event->idx))
if (s.indexOf("%val") != -1) {
if (event->sensorType == SENSOR_TYPE_LONG) {
SMART_REPL(F("%val1%"), String((unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16)))
} else {
SMART_REPL(F("%val1%"), formatUserVar(event, 0))
SMART_REPL(F("%val2%"), formatUserVar(event, 1))
SMART_REPL(F("%val3%"), formatUserVar(event, 2))
SMART_REPL(F("%val4%"), formatUserVar(event, 3))
}
}
}
#undef SMART_REPL
bool getConvertArgument(const String& marker, const String& s, float& argument, int& startIndex, int& endIndex) {
startIndex = s.indexOf(marker);
if (startIndex == -1) return false;
int startIndexArgument = startIndex + marker.length();
if (s.charAt(startIndexArgument) != '(') {
return false;
}
++startIndexArgument;
endIndex = s.indexOf(')', startIndexArgument);
if (endIndex == -1) return false;
String argumentString = s.substring(startIndexArgument, endIndex);
if (argumentString.length() == 0 || !isFloat(argumentString)) return false;
argument = argumentString.toFloat();
++endIndex; // Must also strip ')' from the original string.
return true;
}
// Parse conversions marked with "%conv_marker%(float)"
// Must be called last, since all sensor values must be converted, processed, etc.
void parseStandardConversions(String& s, boolean useURLencode) {
if (s.indexOf(F("%c_")) == -1)
return; // Nothing to replace
float arg = 0.0;
int startIndex = 0;
int endIndex = 0;
// These replacements should be done in a while loop per marker,
// since they also replace the numerical parameter.
// The marker may occur more than once per string, but with different parameters.
#define SMART_CONV(T,FUN) while (getConvertArgument((T), s, arg, startIndex, endIndex)) { repl(s.substring(startIndex, endIndex), (FUN), s, useURLencode); }
SMART_CONV(F("%c_w_dir%"), getBearing(arg))
SMART_CONV(F("%c_c2f%"), toString(CelsiusToFahrenheit(arg), 1))
SMART_CONV(F("%c_ms2Bft%"), String(m_secToBeaufort(arg)))
SMART_CONV(F("%c_cm2imp%"), centimeterToImperialLength(arg))
SMART_CONV(F("%c_mm2imp%"), millimeterToImperialLength(arg))
SMART_CONV(F("%c_m2day%"), toString(minutesToDay(arg), 2))
SMART_CONV(F("%c_m2dh%"), minutesToDayHour(arg))
SMART_CONV(F("%c_m2dhm%"), minutesToDayHourMinute(arg))
SMART_CONV(F("%c_s2dhms%"), secondsToDayHourMinuteSecond(arg))
#undef SMART_CONV
}
-553
View File
@@ -1,553 +0,0 @@
/********************************************************************************************\
Time stuff
\*********************************************************************************************/
#define SECS_PER_MIN (60UL)
#define SECS_PER_HOUR (3600UL)
#define SECS_PER_DAY (SECS_PER_HOUR * 24UL)
#define DAYS_PER_WEEK (7UL)
#define SECS_PER_WEEK (SECS_PER_DAY * DAYS_PER_WEEK)
#define SECS_PER_YEAR (SECS_PER_WEEK * 52UL)
#define SECS_YR_2000 (946684800UL) // the time at the start of y2k
#define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) )
timeStruct tm;
uint32_t syncInterval = 3600; // time sync will be attempted after this many seconds
uint32_t sysTime = 0;
uint32_t prevMillis = 0;
uint32_t nextSyncTime = 0;
byte PrevMinutes = 0;
void breakTime(unsigned long timeInput, struct timeStruct &tm) {
uint8_t year;
uint8_t month, monthLength;
uint32_t time;
unsigned long days;
const uint8_t monthDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
time = (uint32_t)timeInput;
tm.Second = time % 60;
time /= 60; // now it is minutes
tm.Minute = time % 60;
time /= 60; // now it is hours
tm.Hour = time % 24;
time /= 24; // now it is days
tm.Wday = ((time + 4) % 7) + 1; // Sunday is day 1
year = 0;
days = 0;
while ((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) {
year++;
}
tm.Year = year; // year is offset from 1970
days -= LEAP_YEAR(year) ? 366 : 365;
time -= days; // now it is days in this year, starting at 0
days = 0;
month = 0;
monthLength = 0;
for (month = 0; month < 12; month++) {
if (month == 1) { // february
if (LEAP_YEAR(year)) {
monthLength = 29;
} else {
monthLength = 28;
}
} else {
monthLength = monthDays[month];
}
if (time >= monthLength) {
time -= monthLength;
} else {
break;
}
}
tm.Month = month + 1; // jan is month 1
tm.Day = time + 1; // day of month
}
void setTime(unsigned long t) {
sysTime = (uint32_t)t;
nextSyncTime = (uint32_t)t + syncInterval;
prevMillis = millis(); // restart counting from now (thanks to Korman for this fix)
if (Settings.UseRules)
{
static bool firstUpdate = true;
String event = firstUpdate ? F("Time#Initialized") : F("Time#Set");
firstUpdate = false;
rulesProcessing(event);
}
}
unsigned long now() {
// calculate number of seconds passed since last call to now()
const long msec_passed = timePassedSince(prevMillis);
const long seconds_passed = msec_passed / 1000;
sysTime += seconds_passed;
prevMillis += seconds_passed * 1000;
if (nextSyncTime <= sysTime) {
// nextSyncTime & sysTime are in seconds
unsigned long t = getNtpTime();
if (t != 0) {
setTime(t);
applyTimeZone(t);
} else {
// Unable to sync, retry again in a minute
nextSyncTime = sysTime + 60;
}
}
uint32_t localSystime = toLocal(sysTime);
breakTime(localSystime, tm);
return (unsigned long)localSystime;
}
int year(unsigned long t) {
timeStruct tmp;
breakTime(t, tmp);
return 1970 + tmp.Year;
}
int weekday(unsigned long t) {
timeStruct tmp;
breakTime(t, tmp);
return tmp.Wday;
}
int year()
{
return 1970 + tm.Year;
}
byte month()
{
return tm.Month;
}
byte day()
{
return tm.Day;
}
byte hour()
{
return tm.Hour;
}
byte minute()
{
return tm.Minute;
}
byte second()
{
return tm.Second;
}
// day of week, sunday is day 1
int weekday()
{
return tm.Wday;
}
String weekday_str()
{
const int wday(weekday() - 1); // here: Count from Sunday = 0
const String weekDays = F("SunMonTueWedThuFriSat");
return weekDays.substring(wday * 3, wday * 3 + 3);
}
void initTime()
{
nextSyncTime = 0;
now();
}
void checkTime()
{
now();
if (tm.Minute != PrevMinutes)
{
PluginCall(PLUGIN_CLOCK_IN, 0, dummyString);
PrevMinutes = tm.Minute;
if (Settings.UseRules)
{
String event;
event.reserve(21);
event = F("Clock#Time=");
event += weekday_str();
event += ",";
if (hour() < 10)
event += "0";
event += hour();
event += ":";
if (minute() < 10)
event += "0";
event += minute();
rulesProcessing(event);
}
}
}
unsigned long getNtpTime()
{
if (!Settings.UseNTP || !WiFiConnected(100)) {
return 0;
}
IPAddress timeServerIP;
const char* ntpServerName = "pool.ntp.org";
// Have to do a lookup eacht time, since the NTP pool always returns another IP
if (Settings.NTPHost[0] != 0)
WiFi.hostByName(Settings.NTPHost, timeServerIP);
else
WiFi.hostByName(ntpServerName, timeServerIP);
if (!hostReachable(timeServerIP))
return 0;
WiFiUDP udp;
udp.begin(123);
const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets
String log = F("NTP : NTP send to ");
log += timeServerIP.toString();
addLog(LOG_LEVEL_DEBUG_MORE, log);
while (udp.parsePacket() > 0) ; // discard any previously received packets
memset(packetBuffer, 0, NTP_PACKET_SIZE);
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
udp.beginPacket(timeServerIP, 123); //NTP requests are to port 123
udp.write(packetBuffer, NTP_PACKET_SIZE);
udp.endPacket();
uint32_t beginWait = millis();
while (!timeOutReached(beginWait + 1000)) {
int size = udp.parsePacket();
if (size >= NTP_PACKET_SIZE) {
udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer
unsigned long secsSince1900;
// convert four bytes starting at location 40 to a long integer
secsSince1900 = (unsigned long)packetBuffer[40] << 24;
secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
secsSince1900 |= (unsigned long)packetBuffer[43];
log = F("NTP : NTP replied: ");
log += timePassedSince(beginWait);
log += F(" mSec");
addLog(LOG_LEVEL_DEBUG_MORE, log);
return secsSince1900 - 2208988800UL;
}
}
log = F("NTP : No reply");
addLog(LOG_LEVEL_DEBUG_MORE, log);
return 0;
}
/********************************************************************************************\
Unsigned long Timer timeOut check
\*********************************************************************************************/
// Return the time difference as a signed value, taking into account the timers may overflow.
// Returned timediff is between -24.9 days and +24.9 days.
// Returned value is positive when "next" is after "prev"
long timeDiff(unsigned long prev, unsigned long next)
{
long signed_diff = 0;
// To cast a value to a signed long, the difference may not exceed half the ULONG_MAX
const unsigned long half_max_unsigned_long = 2147483647u; // = 2^31 -1
if (next >= prev) {
const unsigned long diff = next - prev;
if (diff <= half_max_unsigned_long) {
// Normal situation, just return the difference.
// Difference is a positive value.
signed_diff = static_cast<long>(diff);
} else {
// prev has overflow, return a negative difference value
signed_diff = static_cast<long>((ULONG_MAX - next) + prev + 1u);
signed_diff = -1 * signed_diff;
}
} else {
// next < prev
const unsigned long diff = prev - next;
if (diff <= half_max_unsigned_long) {
// Normal situation, return a negative difference value
signed_diff = static_cast<long>(diff);
signed_diff = -1 * signed_diff;
} else {
// next has overflow, return a positive difference value
signed_diff = static_cast<long>((ULONG_MAX - prev) + next + 1u);
}
}
return signed_diff;
}
// Compute the number of milliSeconds passed since timestamp given.
// N.B. value can be negative if the timestamp has not yet been reached.
long timePassedSince(unsigned long timestamp) {
return timeDiff(timestamp, millis());
}
// Check if a certain timeout has been reached.
boolean timeOutReached(unsigned long timer)
{
const long passed = timePassedSince(timer);
return passed >= 0;
}
/********************************************************************************************\
Convert a 32 bit integer into a string like "Sun,12:30"
\*********************************************************************************************/
String timeLong2String(unsigned long lngTime)
{
unsigned long x = 0;
String time = "";
x = (lngTime >> 16) & 0xf;
if (x == 0x0f)
x = 0;
String weekDays = F("AllSunMonTueWedThuFriSatWrkWkd");
time = weekDays.substring(x * 3, x * 3 + 3);
time += ",";
x = (lngTime >> 12) & 0xf;
if (x == 0xf)
time += "*";
else if (x == 0xe)
time += "-";
else
time += x;
x = (lngTime >> 8) & 0xf;
if (x == 0xf)
time += "*";
else if (x == 0xe)
time += "-";
else
time += x;
time += ":";
x = (lngTime >> 4) & 0xf;
if (x == 0xf)
time += "*";
else if (x == 0xe)
time += "-";
else
time += x;
x = (lngTime) & 0xf;
if (x == 0xf)
time += "*";
else if (x == 0xe)
time += "-";
else
time += x;
return time;
}
// returns the current Date separated by the given delimiter
// date format example with '-' delimiter: 2016-12-31 (YYYY-MM-DD)
String getDateString(const timeStruct& ts, char delimiter) {
char DateString[20]; //19 digits plus the null char
const int year = 1970 + ts.Year;
sprintf_P(DateString, PSTR("%4d%c%02d%c%02d"), year, delimiter, ts.Month, delimiter, ts.Day);
return DateString;
}
String getDateString(char delimiter)
{
return getDateString(tm, delimiter);
}
// returns the current Date without delimiter
// date format example: 20161231 (YYYYMMDD)
String getDateString()
{
return getDateString('\0');
}
// returns the current Time separated by the given delimiter
// time format example with ':' delimiter: 23:59:59 (HH:MM:SS)
String getTimeString(const timeStruct& ts, char delimiter, bool am_pm, bool show_seconds)
{
char TimeString[20]; //19 digits plus the null char
if (am_pm) {
uint8_t hour(ts.Hour % 12);
if (hour == 0) { hour = 12; }
const char a_or_p = ts.Hour < 12 ? 'A' : 'P';
if (show_seconds) {
sprintf_P(TimeString, PSTR("%d%c%02d%c%02d %cM"),
hour, delimiter, ts.Minute, delimiter, ts.Second, a_or_p);
} else {
sprintf_P(TimeString, PSTR("%d%c%02d %cM"),
hour, delimiter, ts.Minute, a_or_p);
}
} else {
if (show_seconds) {
sprintf_P(TimeString, PSTR("%02d%c%02d%c%02d"),
ts.Hour, delimiter, ts.Minute, delimiter, ts.Second);
} else {
sprintf_P(TimeString, PSTR("%d%c%02d"),
ts.Hour, delimiter, ts.Minute);
}
}
return TimeString;
}
String getTimeString(char delimiter, bool show_seconds /*=true*/)
{
return getTimeString(tm, delimiter, false, show_seconds);
}
String getTimeString_ampm(char delimiter, bool show_seconds /*=true*/)
{
return getTimeString(tm, delimiter, true, show_seconds);
}
// returns the current Time without delimiter
// time format example: 235959 (HHMMSS)
String getTimeString()
{
return getTimeString('\0');
}
String getTimeString_ampm()
{
return getTimeString_ampm('\0');
}
// returns the current Date and Time separated by the given delimiter
// if called like this: getDateTimeString('\0', '\0', '\0');
// it will give back this: 20161231235959 (YYYYMMDDHHMMSS)
String getDateTimeString(const timeStruct& ts, char dateDelimiter, char timeDelimiter, char dateTimeDelimiter, bool am_pm)
{
String ret = getDateString(ts, dateDelimiter);
if (dateTimeDelimiter != '\0')
ret += dateTimeDelimiter;
ret += getTimeString(ts, timeDelimiter, am_pm, true);
return ret;
}
String getDateTimeString(char dateDelimiter, char timeDelimiter, char dateTimeDelimiter) {
return getDateTimeString(tm, dateDelimiter, timeDelimiter, dateTimeDelimiter, false);
}
String getDateTimeString_ampm(char dateDelimiter, char timeDelimiter, char dateTimeDelimiter) {
return getDateTimeString(tm, dateDelimiter, timeDelimiter, dateTimeDelimiter, true);
}
/********************************************************************************************\
Convert a string like "Sun,12:30" into a 32 bit integer
\*********************************************************************************************/
unsigned long string2TimeLong(const String &str)
{
// format 0000WWWWAAAABBBBCCCCDDDD
// WWWW=weekday, AAAA=hours tens digit, BBBB=hours, CCCC=minutes tens digit DDDD=minutes
char command[20];
char TmpStr1[10];
int w, x, y;
unsigned long a;
{
// Within a scope so the tmpString is only used for copy.
String tmpString(str);
tmpString.toLowerCase();
tmpString.toCharArray(command, 20);
}
unsigned long lngTime = 0;
if (GetArgv(command, TmpStr1, 1))
{
String day = TmpStr1;
String weekDays = F("allsunmontuewedthufrisatwrkwkd");
y = weekDays.indexOf(TmpStr1) / 3;
if (y == 0)
y = 0xf; // wildcard is 0xf
lngTime |= (unsigned long)y << 16;
}
if (GetArgv(command, TmpStr1, 2))
{
y = 0;
for (x = strlen(TmpStr1) - 1; x >= 0; x--)
{
w = TmpStr1[x];
if ( (w >= '0' && w <= '9') || w == '*')
{
a = 0xffffffff ^ (0xfUL << y); // create mask to clean nibble position y
lngTime &= a; // maak nibble leeg
if (w == '*')
lngTime |= (0xFUL << y); // fill nibble with wildcard value
else
lngTime |= (w - '0') << y; // fill nibble with token
y += 4;
}
else
if (w == ':');
else
{
break;
}
}
}
return lngTime;
}
/********************************************************************************************\
Match clock event
\*********************************************************************************************/
boolean matchClockEvent(unsigned long clockEvent, unsigned long clockSet)
{
unsigned long Mask;
for (byte y = 0; y < 8; y++)
{
if (((clockSet >> (y * 4)) & 0xf) == 0xf) // if nibble y has the wildcard value 0xf
{
Mask = 0xffffffff ^ (0xFUL << (y * 4)); // Mask to wipe nibble position y.
clockEvent &= Mask; // clear nibble
clockEvent |= (0xFUL << (y * 4)); // fill with wildcard value 0xf
}
}
if (((clockSet >> (16)) & 0xf) == 0x8) // if weekday nibble has the wildcard value 0x8 (workdays)
if (weekday() >= 2 and weekday() <= 6) // and we have a working day today...
{
Mask = 0xffffffff ^ (0xFUL << (16)); // Mask to wipe nibble position.
clockEvent &= Mask; // clear nibble
clockEvent |= (0x8UL << (16)); // fill with wildcard value 0x8
}
if (((clockSet >> (16)) & 0xf) == 0x9) // if weekday nibble has the wildcard value 0x9 (weekends)
if (weekday() == 1 or weekday() == 7) // and we have a weekend day today...
{
Mask = 0xffffffff ^ (0xFUL << (16)); // Mask to wipe nibble position.
clockEvent &= Mask; // clear nibble
clockEvent |= (0x9UL << (16)); // fill with wildcard value 0x9
}
if (clockEvent == clockSet)
return true;
return false;
}
-251
View File
@@ -1,251 +0,0 @@
/********************************************************************************************\
Time zone
\*********************************************************************************************/
// Borrowed code from Timezone: https://github.com/JChristensen/Timezon
TimeChangeRule m_dst; // rule for start of dst or summer time for any year
TimeChangeRule m_std; // rule for start of standard time for any year
uint32_t m_dstUTC = 0; // dst start for given/current year, given in UTC
uint32_t m_stdUTC = 0; // std time start for given/current year, given in UTC
uint32_t m_dstLoc = 0; // dst start for given/current year, given in local time
uint32_t m_stdLoc = 0; // std time start for given/current year, given in local time
/*
// Examples time zones
// Australia Eastern Time Zone (Sydney, Melbourne)
TimeChangeRule aEDT = {First, Sun, Oct, 2, 660}; // UTC + 11 hours
TimeChangeRule aEST = {First, Sun, Apr, 3, 600}; // UTC + 10 hours
setTimeZone(aEDT, aEST);
// Central European Time (Frankfurt, Paris)
TimeChangeRule CEST = {Last, Sun, Mar, 2, 120}; // Central European Summer Time
TimeChangeRule CET = {Last, Sun, Oct, 3, 60}; // Central European Standard Time
setTimeZone(CEST, CET);
// United Kingdom (London, Belfast)
TimeChangeRule BST = {Last, Sun, Mar, 1, 60}; // British Summer Time
TimeChangeRule GMT = {Last, Sun, Oct, 2, 0}; // Standard Time
setTimeZone(BST, GMT);
// UTC
TimeChangeRule utcRule = {Last, Sun, Mar, 1, 0}; // UTC
setTimeZone(utcRule, utcRule);
// US Eastern Time Zone (New York, Detroit)
TimeChangeRule usEDT = {Second, Sun, Mar, 2, -240}; // Eastern Daylight Time = UTC - 4 hours
TimeChangeRule usEST = {First, Sun, Nov, 2, -300}; // Eastern Standard Time = UTC - 5 hours
setTimeZone(usEDT, usEST);
// US Central Time Zone (Chicago, Houston)
TimeChangeRule usCDT = {Second, dowSunday, Mar, 2, -300};
TimeChangeRule usCST = {First, dowSunday, Nov, 2, -360};
setTimeZone(usCDT, usCST);
// US Mountain Time Zone (Denver, Salt Lake City)
TimeChangeRule usMDT = {Second, dowSunday, Mar, 2, -360};
TimeChangeRule usMST = {First, dowSunday, Nov, 2, -420};
setTimeZone(usMDT, usMST);
// Arizona is US Mountain Time Zone but does not use DST
setTimeZone(usMST, usMST);
// US Pacific Time Zone (Las Vegas, Los Angeles)
TimeChangeRule usPDT = {Second, dowSunday, Mar, 2, -420};
TimeChangeRule usPST = {First, dowSunday, Nov, 2, -480};
setTimeZone(usPDT, usPST);
*/
void getDefaultDst_flash_values(uint16_t& start, uint16_t& end) {
// DST start: Last Sunday March 2am => 3am
// DST end: Last Sunday October 3am => 2am
TimeChangeRule CEST(Last, Sun, Mar, 2, Settings.TimeZone); // Summer Time
TimeChangeRule CET(Last, Sun, Oct, 3, Settings.TimeZone); // Standard Time
start = CEST.toFlashStoredValue();
end = CET.toFlashStoredValue();
}
void applyTimeZone(uint32_t curTime) {
int dst_offset = Settings.DST ? 60 : 0;
uint16_t tmpStart(Settings.DST_Start);
uint16_t tmpEnd(Settings.DST_End);
for (int i = 0; i < 2; ++i) {
TimeChangeRule start(tmpStart, Settings.TimeZone + dst_offset); // Summer Time
TimeChangeRule end(tmpEnd, Settings.TimeZone); // Standard Time
if (start.isValid() && end.isValid()) {
setTimeZone(start, end, curTime);
return;
}
getDefaultDst_flash_values(tmpStart, tmpEnd);
}
}
void setTimeZone(const TimeChangeRule& dstStart, const TimeChangeRule& stdStart, uint32_t curTime) {
m_dst = dstStart;
m_std = stdStart;
if (calcTimeChanges(year(curTime))) {
logTimeZoneInfo();
}
}
void logTimeZoneInfo() {
String log = F("Current Time Zone: ");
if (m_std.offset != m_dst.offset) {
// Summer time
log += F(" DST time start: ");
if (m_dstLoc != 0) {
timeStruct tmp;
breakTime(m_dstLoc, tmp);
log += getDateTimeString(tmp, '-', ':', ' ', false);
}
log += F(" offset: ");
log += m_dst.offset;
log += F(" min");
}
// Standard/Winter time.
log += F("STD time start: ");
if (m_stdLoc != 0) {
timeStruct tmp;
breakTime(m_stdLoc, tmp);
log += getDateTimeString(tmp, '-', ':', ' ', false);
}
log += F(" offset: ");
log += m_std.offset;
log += F(" min");
addLog(LOG_LEVEL_INFO, log);
}
uint32_t makeTime(const timeStruct &tm) {
// assemble time elements into uint32_t
// note year argument is offset from 1970 (see macros in time.h to convert to other formats)
// previous version used full four digit year (or digits since 2000),i.e. 2009 was 2009 or 9
const uint8_t monthDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int i;
uint32_t seconds;
// seconds from 1970 till 1 jan 00:00:00 of the given year
seconds= tm.Year*(SECS_PER_DAY * 365);
for (i = 0; i < tm.Year; i++) {
if (LEAP_YEAR(i)) {
seconds += SECS_PER_DAY; // add extra days for leap years
}
}
// add days for this year, months start from 1
for (i = 1; i < tm.Month; i++) {
if ( (i == 2) && LEAP_YEAR(tm.Year)) {
seconds += SECS_PER_DAY * 29;
} else {
seconds += SECS_PER_DAY * monthDays[i-1]; //monthDay array starts from 0
}
}
seconds+= (tm.Day-1) * SECS_PER_DAY;
seconds+= tm.Hour * SECS_PER_HOUR;
seconds+= tm.Minute * SECS_PER_MIN;
seconds+= tm.Second;
return (uint32_t)seconds;
}
///*----------------------------------------------------------------------*
// * Convert the given time change rule to a uint32_t value *
// * for the given year. *
// *----------------------------------------------------------------------*/
uint32_t calcTimeChangeForRule(const TimeChangeRule& r, int yr)
{
uint8_t m = r.month; // temp copies of r.month and r.week
uint8_t w = r.week;
if (w == 0) // is this a "Last week" rule?
{
if (++m > 12) // yes, for "Last", go to the next month
{
m = 1;
++yr;
}
w = 1; // and treat as first week of next month, subtract 7 days later
}
// calculate first day of the month, or for "Last" rules, first day of the next month
timeStruct tm;
tm.Hour = r.hour;
tm.Minute = 0;
tm.Second = 0;
tm.Day = 1;
tm.Month = m;
tm.Year = yr - 1970;
uint32_t t = makeTime(tm);
// add offset from the first of the month to r.dow, and offset for the given week
t += ( (r.dow - weekday(t) + 7) % 7 + (w - 1) * 7 ) * SECS_PER_DAY;
// back up a week if this is a "Last" rule
if (r.week == 0) t -= 7 * SECS_PER_DAY;
return t;
}
/*----------------------------------------------------------------------*
* Calculate the DST and standard time change points for the given *
* given year as local and UTC uint32_t values. *
*----------------------------------------------------------------------*/
bool calcTimeChanges(int yr)
{
uint32_t dstLoc = calcTimeChangeForRule(m_dst, yr);
uint32_t stdLoc = calcTimeChangeForRule(m_std, yr);
bool changed = (m_dstLoc != dstLoc) || (m_stdLoc != stdLoc);
m_dstLoc = dstLoc;
m_stdLoc = stdLoc;
m_dstUTC = m_dstLoc - m_std.offset * SECS_PER_MIN;
m_stdUTC = m_stdLoc - m_dst.offset * SECS_PER_MIN;
return changed;
}
/*----------------------------------------------------------------------*
* Convert the given UTC time to local time, standard or *
* daylight time, as appropriate. *
*----------------------------------------------------------------------*/
uint32_t toLocal(uint32_t utc)
{
// recalculate the time change points if needed
if (year(utc) != year(m_dstUTC)) calcTimeChanges(year(utc));
if (utcIsDST(utc))
return utc + m_dst.offset * SECS_PER_MIN;
else
return utc + m_std.offset * SECS_PER_MIN;
}
/*----------------------------------------------------------------------*
* Determine whether the given UTC uint32_t is within the DST interval *
* or the Standard time interval. *
*----------------------------------------------------------------------*/
bool utcIsDST(uint32_t utc)
{
// recalculate the time change points if needed
if (year(utc) != year(m_dstUTC)) calcTimeChanges(year(utc));
if (m_stdUTC == m_dstUTC) // daylight time not observed in this tz
return false;
else if (m_stdUTC > m_dstUTC) // northern hemisphere
return (utc >= m_dstUTC && utc < m_stdUTC);
else // southern hemisphere
return !(utc >= m_stdUTC && utc < m_dstUTC);
}
/*----------------------------------------------------------------------*
* Determine whether the given Local uint32_t is within the DST interval *
* or the Standard time interval. *
*----------------------------------------------------------------------*/
bool locIsDST(uint32_t local)
{
// recalculate the time change points if needed
if (year(local) != year(m_dstLoc)) calcTimeChanges(year(local));
if (m_stdUTC == m_dstUTC) // daylight time not observed in this tz
return false;
else if (m_stdLoc > m_dstLoc) // northern hemisphere
return (local >= m_dstLoc && local < m_stdLoc);
else // southern hemisphere
return !(local >= m_stdLoc && local < m_dstLoc);
}
+1463 -1983
View File
File diff suppressed because it is too large Load Diff
+158 -290
View File
@@ -4,7 +4,7 @@
String WifiGetAPssid()
{
String ssid(Settings.Name);
ssid+=F("-");
ssid+=F("_");
ssid+=Settings.Unit;
return (ssid);
}
@@ -27,10 +27,7 @@ void WifiAPconfig()
{
// create and store unique AP SSID/PW to prevent ESP from starting AP mode with default SSID and No password!
// setup ssid for AP Mode when needed
String softAPSSID=WifiGetAPssid();
String pwd = SecuritySettings.WifiAPKey;
WiFi.softAP(softAPSSID.c_str(),pwd.c_str());
WiFi.softAP(WifiGetAPssid().c_str(), SecuritySettings.WifiAPKey);
// We start in STA mode
WifiAPMode(false);
@@ -47,7 +44,12 @@ void WifiAPconfig()
bool WifiIsAP()
{
byte wifimode = wifi_get_opmode();
#if defined(ESP8266)
byte wifimode = wifi_get_opmode();
#endif
#if defined(ESP32)
byte wifimode = WiFi.getMode();
#endif
return(wifimode == 2 || wifimode == 3); //apmode is enabled
}
@@ -77,307 +79,154 @@ void WifiAPMode(boolean state)
}
//********************************************************************************
// Set Wifi config
//********************************************************************************
bool prepareWiFi() {
String log = "";
char hostname[40];
strncpy(hostname, WifiGetHostname().c_str(), sizeof(hostname));
wifi_station_set_hostname(hostname);
//use static ip?
if (Settings.IP[0] != 0 && Settings.IP[0] != 255)
{
char str[20];
sprintf_P(str, PSTR("%u.%u.%u.%u"), Settings.IP[0], Settings.IP[1], Settings.IP[2], Settings.IP[3]);
log = F("IP : Static IP :");
log += str;
addLog(LOG_LEVEL_INFO, log);
IPAddress ip = Settings.IP;
IPAddress gw = Settings.Gateway;
IPAddress subnet = Settings.Subnet;
IPAddress dns = Settings.DNS;
WiFi.config(ip, gw, subnet, dns);
}
return selectValidWiFiSettings();
}
//********************************************************************************
// Configure network and connect to Wifi SSID and SSID2
//********************************************************************************
boolean WifiConnect(byte connectAttempts)
{
if (prepareWiFi()) {
//try to connect to one of the access points
bool connected = WifiConnectAndWait(connectAttempts);
if (!connected) {
if (selectNextWiFiSettings()) {
connected = WifiConnectAndWait(connectAttempts);
}
}
if (connected) {
return(true);
}
String log = "";
char hostname[40];
strncpy(hostname, WifiGetHostname().c_str(), sizeof(hostname));
#if defined(ESP8266)
wifi_station_set_hostname(hostname);
#endif
#if defined(ESP32)
WiFi.setHostname(hostname);
#endif
//use static ip?
if (Settings.IP[0] != 0 && Settings.IP[0] != 255)
{
const IPAddress ip = Settings.IP;
log = F("IP : Static IP :");
log += ip;
addLog(LOG_LEVEL_INFO, log);
const IPAddress gw = Settings.Gateway;
const IPAddress subnet = Settings.Subnet;
const IPAddress dns = Settings.DNS;
WiFi.config(ip, gw, subnet, dns);
}
//try to connect to one of the access points
if (WifiConnectSSID(SecuritySettings.WifiSSID, SecuritySettings.WifiKey, connectAttempts) ||
WifiConnectSSID(SecuritySettings.WifiSSID2, SecuritySettings.WifiKey2, connectAttempts))
{
// fix octet?
if (Settings.IP_Octet != 0 && Settings.IP_Octet != 255)
{
IPAddress ip = WiFi.localIP();
IPAddress gw = WiFi.gatewayIP();
IPAddress subnet = WiFi.subnetMask();
ip[3] = Settings.IP_Octet;
log = F("IP : Fixed IP octet:");
log += ip;
addLog(LOG_LEVEL_INFO, log);
WiFi.config(ip, gw, subnet);
}
#ifdef FEATURE_MDNS
String log = F("WIFI : ");
if (MDNS.begin(WifiGetHostname().c_str(), WiFi.localIP())) {
log += F("mDNS started, with name: ");
log += WifiGetHostname();
log += F(".local");
}
else{
log += F("mDNS failed");
}
addLog(LOG_LEVEL_INFO, log);
#endif
return(true);
}
addLog(LOG_LEVEL_ERROR, F("WIFI : Could not connect to AP!"));
//everything failed, activate AP mode (will deactivate automatically after a while if its connected again)
WifiAPMode(true);
return(false);
}
//********************************************************************************
// Start connect to WiFi and check later to see if connected.
//********************************************************************************
void WiFiConnectRelaxed() {
wifiConnected = false;
wifi_connect_attempt = 0;
if (prepareWiFi()) {
tryConnectWiFi();
return;
}
addLog(LOG_LEVEL_ERROR, F("WIFI : Could not connect to AP, no valid WiFi settings!"));
//everything failed, activate AP mode (will deactivate automatically after a while if its connected again)
WifiAPMode(true);
}
//********************************************************************************
// Manage WiFi credentials
//********************************************************************************
const char* getLastWiFiSettingsSSID() {
return lastWiFiSettings == 0 ? SecuritySettings.WifiSSID : SecuritySettings.WifiSSID2;
}
const char* getLastWiFiSettingsPassphrase() {
return lastWiFiSettings == 0 ? SecuritySettings.WifiKey : SecuritySettings.WifiKey2;
}
bool anyValidWifiSettings() {
if (wifiSettingsValid(SecuritySettings.WifiSSID, SecuritySettings.WifiKey))
return true;
if (wifiSettingsValid(SecuritySettings.WifiSSID2, SecuritySettings.WifiKey2))
return true;
addLog(LOG_LEVEL_ERROR, F("WIFI : No valid WiFi settings!"));
return false;
}
bool selectNextWiFiSettings() {
uint8_t tmp = lastWiFiSettings;
lastWiFiSettings = (lastWiFiSettings + 1) % 2;
if (!wifiSettingsValid(getLastWiFiSettingsSSID(), getLastWiFiSettingsPassphrase())) {
// other settings are not correct, switch back.
lastWiFiSettings = tmp;
return false; // Nothing changed.
}
return true;
}
bool selectValidWiFiSettings() {
if (wifiSettingsValid(getLastWiFiSettingsSSID(), getLastWiFiSettingsPassphrase()))
return true;
return selectNextWiFiSettings();
}
bool wifiSettingsValid(const char* ssid, const char* pass) {
if (ssid[0] == 0 || (strcasecmp(ssid, "ssid") == 0)) {
return false;
}
if (pass[0] == 0) return false;
if (strlen(ssid) > 32) return false;
if (strlen(pass) > 64) return false;
return true;
}
bool wifiConnectTimeoutReached() {
if (wifi_connect_attempt == 0) return true;
if (wifiSetupConnect) {
// Initial setup of WiFi, may take much longer since accesspoint is still active.
return timeOutReached(wifi_connect_timer + 20000);
}
// wait until it connects + add some device specific random offset to prevent
// all nodes overloading the accesspoint when turning on at the same time.
const unsigned int randomOffset_in_sec = wifi_connect_attempt == 1 ? 0 : 1000 * ((ESP.getChipId() & 0xF));
return timeOutReached(wifi_connect_timer + DEFAULT_WIFI_CONNECTION_TIMEOUT + randomOffset_in_sec);
}
//********************************************************************************
// Simply start the WiFi connection sequence
//********************************************************************************
bool tryConnectWiFi() {
if (wifiSetup && !wifiSetupConnect)
return false;
if (WiFi.status() == WL_CONNECTED)
return(true); //already connected, need to disconnect first
if (!wifiConnectTimeoutReached())
return true; // timeout not reached yet, thus no need to retry again.
if (!anyValidWifiSettings())
return false;
if (wifi_connect_attempt != 0 && ((wifi_connect_attempt % 3) == 0)) {
// Change to other wifi settings.
if (selectNextWiFiSettings())
WiFi.disconnect();
}
if (wifi_connect_attempt > 6) {
//everything failed, activate AP mode (will deactivate automatically after a while if its connected again)
WifiAPMode(true);
}
String ssid;
ssid.reserve(32);
String passphrase;
passphrase.reserve(64);
ssid = getLastWiFiSettingsSSID();
passphrase = getLastWiFiSettingsPassphrase();
String log = F("WIFI : Connecting ");
log += ssid;
log += F(" attempt #");
log += wifi_connect_attempt;
addLog(LOG_LEVEL_INFO, log);
wifi_connect_timer = millis();
switch (wifi_connect_attempt) {
case 0:
if (lastBSSID[0] == 0)
WiFi.begin(ssid.c_str(), passphrase.c_str());
else
WiFi.begin(ssid.c_str(), passphrase.c_str(), 0, &lastBSSID[0]);
break;
default:
WiFi.begin(ssid.c_str(), passphrase.c_str());
}
++wifi_connect_attempt;
switch (WiFi.status()) {
case WL_NO_SSID_AVAIL: {
log = F("WIFI : No SSID found matching: ");
log += ssid;
addLog(LOG_LEVEL_INFO, log);
return false;
}
case WL_CONNECT_FAILED: {
log = F("WIFI : Connection failed to: ");
log += ssid;
addLog(LOG_LEVEL_INFO, log);
return false;
}
case WL_CONNECTED:
checkWifiJustConnected();
break;
default:
break;
}
return true; // Sent
}
//********************************************************************************
// Connect to Wifi specific SSID
//********************************************************************************
boolean WifiConnectAndWait(byte connectAttempts)
boolean WifiConnectSSID(char WifiSSID[], char WifiKey[], byte connectAttempts)
{
String log;
wifiConnected = false;
wifi_connect_attempt = 0;
for (byte tryConnect = 0; tryConnect < connectAttempts; tryConnect++)
//already connected, need to disconnect first
if (WiFi.status() == WL_CONNECTED)
return(true);
//no ssid specified
if ((WifiSSID[0] == 0) || (strcasecmp(WifiSSID, "ssid") == 0))
return(false);
for (byte tryConnect = 1; tryConnect <= connectAttempts; tryConnect++)
{
if (tryConnectWiFi()) {
do {
if (checkWifiJustConnected())
return true;
delay(50);
} while (!wifiConnectTimeoutReached());
}
// log = F("WIFI : Disconnecting!");
// addLog(LOG_LEVEL_INFO, log);
#if defined(ESP8266)
ETS_UART_INTR_DISABLE();
wifi_station_disconnect();
ETS_UART_INTR_ENABLE();
#endif
for (byte x = 0; x < 20; x++)
log = F("WIFI : Connecting ");
log += WifiSSID;
log += F(" attempt #");
log += tryConnect;
addLog(LOG_LEVEL_INFO, log);
if (tryConnect == 1)
WiFi.begin(WifiSSID, WifiKey);
else
WiFi.begin();
//wait until it connects
for (byte x = 0; x < 200; x++)
{
if (WiFi.status() != WL_CONNECTED)
{
statusLED(false);
delay(50);
}
else
break;
}
if (WiFi.status() == WL_CONNECTED)
{
if (Settings.UseNTP) {
initTime();
}
log = F("WIFI : Connected! IP: ");
log += formatIP(WiFi.localIP());
log += F(" (");
log += WifiGetHostname();
log += F(")");
addLog(LOG_LEVEL_INFO, log);
statusLED(true);
delay(50);
return(true);
}
else
{
// log = F("WIFI : Disconnecting!");
// addLog(LOG_LEVEL_INFO, log);
#if defined(ESP8266)
ETS_UART_INTR_DISABLE();
wifi_station_disconnect();
ETS_UART_INTR_ENABLE();
#endif
for (byte x = 0; x < 20; x++)
{
statusLED(true);
delay(50);
}
}
}
return false;
}
bool checkWifiJustConnected() {
if (wifiConnected) return true;
delay(1);
if (WiFi.status() != WL_CONNECTED) {
statusLED(false);
return false;
}
wifiConnected = true;
String log = F("WIFI : WiFi connect attempt took: ");
log += timePassedSince(wifi_connect_timer);
log += F(" ms");
addLog(LOG_LEVEL_INFO, log);
// fix octet?
if (Settings.IP_Octet != 0 && Settings.IP_Octet != 255)
{
IPAddress ip = WiFi.localIP();
IPAddress gw = WiFi.gatewayIP();
IPAddress subnet = WiFi.subnetMask();
ip[3] = Settings.IP_Octet;
log = F("IP : Fixed IP octet:");
log += ip;
addLog(LOG_LEVEL_INFO, log);
WiFi.config(ip, gw, subnet);
}
#ifdef FEATURE_MDNS
String log = F("WIFI : ");
if (MDNS.begin(WifiGetHostname().c_str(), WiFi.localIP())) {
log += F("mDNS started, with name: ");
log += WifiGetHostname();
log += F(".local");
}
else{
log += F("mDNS failed");
}
addLog(LOG_LEVEL_INFO, log);
#endif
// First try to get the time, since that may be used in logs
if (Settings.UseNTP) {
initTime();
}
uint8_t* curBSSID = WiFi.BSSID();
bool changed = false;
for (byte i=0; i < 6; ++i) {
if (lastBSSID[i] != *(curBSSID + i)) {
changed = true;
lastBSSID[i] = *(curBSSID + i);
}
}
if (Settings.UseRules)
{
if (changed) {
String event = F("WiFi#ChangedAccesspoint");
rulesProcessing(event);
}
String event = F("WiFi#Connected");
rulesProcessing(event);
}
log = F("WIFI : Connected! IP: ");
log += formatIP(WiFi.localIP());
log += F(" (");
log += WifiGetHostname();
log += F(") AP: ");
log += WiFi.SSID();
log += F(" AP BSSID: ");
log += WiFi.BSSIDstr();
addLog(LOG_LEVEL_INFO, log);
statusLED(true);
return true;
}
//********************************************************************************
// Disconnect from Wifi AP
@@ -385,7 +234,6 @@ bool checkWifiJustConnected() {
void WifiDisconnect()
{
WiFi.disconnect();
wifiConnected = false;
}
@@ -427,20 +275,18 @@ void WifiScan()
//********************************************************************************
void WifiCheck()
{
if(wifiSetup)
return;
if (WiFi.status() != WL_CONNECTED)
{
NC_Count++;
//give it time to automaticly reconnect
//give it time to automatically reconnect
if (NC_Count > 2)
{
if (wifiConnected) {
wifi_connect_attempt = 0;
wifiConnected = false;
WiFiConnectRelaxed();
}
WifiConnect(2);
C_Count=0;
NC_Count = 0;
}
@@ -455,8 +301,30 @@ void WifiCheck()
WifiAPMode(false);
}
}
if (!wifiConnected) {
if (tryConnectWiFi())
checkWifiJustConnected();
}
//********************************************************************************
// Return subnet range of WiFi.
//********************************************************************************
bool getSubnetRange(IPAddress& low, IPAddress& high)
{
if (WifiIsAP()) {
// WiFi is active as accesspoint, do not check.
return false;
}
if (WiFi.status() != WL_CONNECTED) {
return false;
}
const IPAddress ip = WiFi.localIP();
const IPAddress subnet = WiFi.subnetMask();
low = ip;
high = ip;
// Compute subnet range.
for (byte i=0; i < 4; ++i) {
if (subnet[i] != 255) {
low[i] = low[i] & subnet[i];
high[i] = high[i] | ~subnet[i];
}
}
return true;
}
+91 -27
View File
@@ -6,6 +6,7 @@
#define CPLUGIN_ID_001 1
#define CPLUGIN_NAME_001 "Domoticz HTTP"
boolean CPlugin_001(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
@@ -33,7 +34,7 @@ boolean CPlugin_001(byte function, struct EventStruct *event, String& string)
{
if (event->idx != 0)
{
if (!WiFiConnected(100)) {
if (WiFi.status() != WL_CONNECTED) {
success = false;
break;
}
@@ -75,6 +76,64 @@ boolean CPlugin_001(byte function, struct EventStruct *event, String& string)
switch (event->sensorType)
{
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
url += F("&svalue=");
url += formatUserVar(event, 0);
break;
case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags)
url += F("&svalue=");
url += (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
break;
case SENSOR_TYPE_DUAL: // any sensor that uses two simple values
url += F("&svalue=");
url += formatUserVar(event, 0);
url += (";");
url += formatUserVar(event, 1);
break;
case SENSOR_TYPE_TEMP_HUM: // temp + hum + hum_stat, used for DHT11
url += F("&svalue=");
url += formatUserVar(event, 0);
url += F(";");
url += formatUserVar(event, 1);
url += F(";");
url += humStat(UserVar[event->BaseVarIndex + 1]);
break;
case SENSOR_TYPE_TEMP_BARO: // temp + bar used for BMP085 and BMP280
url += F("&svalue=");
url += formatUserVar(event, 0);
url += F(";");
url += formatUserVar(event, 1);
url += F(";0;0;");
break;
case SENSOR_TYPE_TRIPLE:
url += F("&svalue=");
url += formatUserVar(event, 0);
url += F(";");
url += formatUserVar(event, 1);
url += F(";");
url += formatUserVar(event, 2);
break;
case SENSOR_TYPE_TEMP_HUM_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BME280
url += F("&svalue=");
url += formatUserVar(event, 0);
url += F(";");
url += formatUserVar(event, 1);
url += F(";");
url += humStat(UserVar[event->BaseVarIndex + 1]);
url += F(";");
url += formatUserVar(event, 2);
url += F(";0");
break;
case SENSOR_TYPE_QUAD:
url += F("&svalue=");
url += formatUserVar(event, 0);
url += F(";");
url += formatUserVar(event, 1);
url += F(";");
url += formatUserVar(event, 2);
url += F(";");
url += formatUserVar(event, 3);
break;
case SENSOR_TYPE_SWITCH:
url = F("/json.htm?type=command&param=switchlight&idx=");
url += event->idx;
@@ -88,39 +147,28 @@ boolean CPlugin_001(byte function, struct EventStruct *event, String& string)
url = F("/json.htm?type=command&param=switchlight&idx=");
url += event->idx;
url += F("&switchcmd=");
if (UserVar[event->BaseVarIndex] == 0) {
if (UserVar[event->BaseVarIndex] == 0)
url += ("Off");
} else {
else
{
url += F("Set%20Level&level=");
url += UserVar[event->BaseVarIndex];
}
break;
case SENSOR_TYPE_SINGLE:
case SENSOR_TYPE_LONG:
case SENSOR_TYPE_DUAL:
case SENSOR_TYPE_TRIPLE:
case SENSOR_TYPE_QUAD:
case SENSOR_TYPE_TEMP_HUM:
case SENSOR_TYPE_TEMP_BARO:
case SENSOR_TYPE_TEMP_HUM_BARO:
case SENSOR_TYPE_WIND:
default:
url = F("/json.htm?type=command&param=udevice&idx=");
url += event->idx;
url += F("&nvalue=0");
url += F("&svalue=");
url += formatDomoticzSensorType(event);
case (SENSOR_TYPE_WIND):
url += F("&svalue="); // WindDir in degrees; WindDir as text; Wind speed average ; Wind speed gust; 0
url += formatUserVar(event, 0);
url += ";";
url += getBearing(UserVar[event->BaseVarIndex]);
url += ";";
// Domoticz expects the wind speed in (m/s * 10)
url += toString((UserVar[event->BaseVarIndex + 1] * 10),ExtraTaskSettings.TaskDeviceValueDecimals[1]);
url += ";";
url += toString((UserVar[event->BaseVarIndex + 2] * 10),ExtraTaskSettings.TaskDeviceValueDecimals[2]);
url += ";0";
break;
}
// Add WiFi reception quality
url += F("&rssi=");
url += mapRSSItoDomoticz();
#if FEATURE_ADC_VCC
url += F("&battery=");
url += mapVccToDomoticz();
#endif
// This will send the request to the server
String request = F("GET ");
@@ -134,7 +182,7 @@ boolean CPlugin_001(byte function, struct EventStruct *event, String& string)
client.print(request);
unsigned long timer = millis() + 200;
while (!client.available() && !timeOutReached(timer))
while (!client.available() && !timeOutReached(timer))
yield();
// Read all the lines of the reply from server and log them
@@ -164,3 +212,19 @@ boolean CPlugin_001(byte function, struct EventStruct *event, String& string)
}
return success;
}
int humStat(int hum){
int lHumStat;
if(hum<30){
lHumStat = 2;
}else if(hum<40){
lHumStat = 0;
}else if(hum<59){
lHumStat = 1;
}else{
lHumStat = 3;
}
return lHumStat;
}
+161 -95
View File
@@ -44,86 +44,81 @@ boolean CPlugin_002(byte function, struct EventStruct *event, String& string)
// char json[512];
// json[0] = 0;
// event->String2.toCharArray(json, 512);
// Find first enabled controller index with this protocol
byte ControllerID = findFirstEnabledControllerWithId(CPLUGIN_ID_002);
if (ControllerID < CONTROLLER_MAX) {
StaticJsonBuffer<512> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(event->String2.c_str());
if (root.success())
{
unsigned int idx = root[F("idx")];
float nvalue = root[F("nvalue")];
long nvaluealt = root[F("nvalue")];
//const char* name = root["name"]; // Not used
//const char* svalue = root["svalue"]; // Not used
const char* svalue1 = root[F("svalue1")];
//const char* svalue2 = root["svalue2"]; // Not used
//const char* svalue3 = root["svalue3"]; // Not used
const char* switchtype = root[F("switchType")]; // Expect "On/Off" or "dimmer"
if (nvalue == 0)
nvalue = nvaluealt;
if ((int)switchtype == 0)
switchtype = "?";
for (byte x = 0; x < TASKS_MAX; x++) {
// We need the index of the controller we are: 0...CONTROLLER_MAX
if (Settings.TaskDeviceEnabled[x] && Settings.TaskDeviceID[ControllerID][x] == idx) // get idx for our controller index
StaticJsonBuffer<512> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(event->String2.c_str());
if (root.success())
{
unsigned int idx = root[F("idx")];
float nvalue = root[F("nvalue")];
long nvaluealt = root[F("nvalue")];
//const char* name = root["name"]; // Not used
//const char* svalue = root["svalue"]; // Not used
const char* svalue1 = root[F("svalue1")];
//const char* svalue2 = root["svalue2"]; // Not used
//const char* svalue3 = root["svalue3"]; // Not used
const char* switchtype = root[F("switchType")]; // Expect "On/Off" or "dimmer"
if (nvalue == 0)
nvalue = nvaluealt;
if ((int)switchtype == 0)
switchtype = "?";
for (byte x = 0; x < TASKS_MAX; x++) {
// We need the index of the controller we are: 0-CONTROLLER_MAX
byte ControllerID = 0;
for (byte i=0; i < CONTROLLER_MAX; i++)
{
if (Settings.Protocol[i] == CPLUGIN_ID_002) { ControllerID = i; }
}
if (Settings.TaskDeviceID[ControllerID][x] == idx) // get idx for our controller index
{
if (Settings.TaskDeviceNumber[x] == 1) // temp solution, if input switch, update state
{
String action = F("inputSwitchState,");
action += x;
action += ",";
action += nvalue;
struct EventStruct TempEvent;
parseCommandString(&TempEvent, action);
PluginCall(PLUGIN_WRITE, &TempEvent, action);
}
if (Settings.TaskDeviceNumber[x] == 29) // temp solution, if plugin 029, set gpio
{
String action = "";
switch (Settings.TaskDeviceNumber[x]) {
case 1: // temp solution, if input switch, update state
int baseVar = x * VARS_PER_TASK;
struct EventStruct TempEvent;
if (strcasecmp_P(switchtype, PSTR("dimmer")) == 0)
{
int pwmValue = UserVar[baseVar];
action = F("pwm,");
action += Settings.TaskDevicePin1[x];
action += ",";
switch ((int)nvalue)
{
action = F("inputSwitchState,");
action += x;
action += ",";
action += nvalue;
break;
case 0:
pwmValue = 0;
break;
case 1:
pwmValue = UserVar[baseVar];
break;
case 2:
pwmValue = 10 * atol(svalue1);
UserVar[baseVar] = pwmValue;
break;
}
case 29: // temp solution, if plugin 029, set gpio
{
action = "";
int baseVar = x * VARS_PER_TASK;
struct EventStruct TempEvent;
if (strcasecmp_P(switchtype, PSTR("dimmer")) == 0)
{
int pwmValue = UserVar[baseVar];
action = F("pwm,");
action += Settings.TaskDevicePin1[x];
action += ",";
switch ((int)nvalue)
{
case 0:
pwmValue = 0;
break;
case 1:
pwmValue = UserVar[baseVar];
break;
case 2:
pwmValue = 10 * atol(svalue1);
UserVar[baseVar] = pwmValue;
break;
}
action += pwmValue;
} else {
UserVar[baseVar] = nvalue;
action = F("gpio,");
action += Settings.TaskDevicePin1[x];
action += ",";
action += nvalue;
}
break;
}
default:
break;
action += pwmValue;
}
if (action.length() > 0) {
struct EventStruct TempEvent;
parseCommandString(&TempEvent, action);
PluginCall(PLUGIN_WRITE, &TempEvent, action);
// trigger rulesprocessing
if (Settings.UseRules)
createRuleEvents(x);
else
{
UserVar[baseVar] = nvalue;
action = F("gpio,");
action += Settings.TaskDevicePin1[x];
action += ",";
action += nvalue;
}
parseCommandString(&TempEvent, action);
PluginCall(PLUGIN_WRITE, &TempEvent, action);
}
}
}
@@ -135,23 +130,88 @@ boolean CPlugin_002(byte function, struct EventStruct *event, String& string)
{
if (event->idx != 0)
{
ControllerSettingsStruct ControllerSettings;
LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
if (!ControllerSettings.checkHostReachable(true)) {
if (WiFi.status() != WL_CONNECTED) {
success = false;
break;
}
ControllerSettingsStruct ControllerSettings;
LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
StaticJsonBuffer<200> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root[F("idx")] = event->idx;
root[F("RSSI")] = mapRSSItoDomoticz();
#if FEATURE_ADC_VCC
root[F("Battery")] = mapVccToDomoticz();
#endif
String values;
// char str[80];
switch (event->sensorType)
{
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
root[F("nvalue")] = 0;
values = formatUserVar(event, 0);
// values.toCharArray(str, 80);
root[F("svalue")] = values.c_str();
break;
case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags)
root[F("nvalue")] = 0;
values = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
// values.toCharArray(str, 80);
root[F("svalue")] = values.c_str();
break;
case SENSOR_TYPE_DUAL: // any sensor that uses two simple values
root[F("nvalue")] = 0;
values = formatUserVar(event, 0);
values += ";";
values += formatUserVar(event, 1);
// values.toCharArray(str, 80);
root[F("svalue")] = values.c_str();
// root[F("svalue")] = str;
break;
case SENSOR_TYPE_TRIPLE: // any sensor that uses three simple values
root[F("nvalue")] = 0;
values = toString(UserVar[event->BaseVarIndex ], ExtraTaskSettings.TaskDeviceValueDecimals[0]);
values += ";";
values += toString(UserVar[event->BaseVarIndex + 1], ExtraTaskSettings.TaskDeviceValueDecimals[1]);
values += ";";
values += toString(UserVar[event->BaseVarIndex + 2], ExtraTaskSettings.TaskDeviceValueDecimals[2]);
// values.toCharArray(str, 80);
root[F("svalue")] = values.c_str();
// root[F("svalue")] = str;
break;
case SENSOR_TYPE_TEMP_HUM: // temp + hum + hum_stat, used for DHT11
root[F("nvalue")] = 0;
values = formatUserVar(event, 0);
values += ";";
values += formatUserVar(event, 1);
values += ";0";
// values.toCharArray(str, 80);
root[F("svalue")] = values.c_str();
// root[F("svalue")] = str;
break;
case SENSOR_TYPE_TEMP_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BMP085
root[F("nvalue")] = 0;
values = formatUserVar(event, 0);
values += formatUserVar(event, 1);
values += ";0;0;";
// values.toCharArray(str, 80);
root[F("svalue")] = values.c_str();
// root[F("svalue")] = str;
break;
case SENSOR_TYPE_TEMP_HUM_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BME280
root[F("nvalue")] = 0;
values = formatUserVar(event, 0);
values += ";";
values += formatUserVar(event, 1);
values += ";0;";
values += formatUserVar(event, 2);
values += ";0";
root[F("svalue")] = values.c_str();
// values.toCharArray(str, 80);
// root[F("svalue")] = str;
break;
case SENSOR_TYPE_SWITCH:
root[F("command")] = String(F("switchlight"));
if (UserVar[event->BaseVarIndex] == 0)
@@ -166,19 +226,19 @@ boolean CPlugin_002(byte function, struct EventStruct *event, String& string)
else
root[F("Set%20Level")] = UserVar[event->BaseVarIndex];
break;
case SENSOR_TYPE_SINGLE:
case SENSOR_TYPE_LONG:
case SENSOR_TYPE_DUAL:
case SENSOR_TYPE_TRIPLE:
case SENSOR_TYPE_QUAD:
case SENSOR_TYPE_TEMP_HUM:
case SENSOR_TYPE_TEMP_BARO:
case SENSOR_TYPE_TEMP_HUM_BARO:
case SENSOR_TYPE_WIND:
default:
root[F("nvalue")] = 0;
root[F("svalue")] = formatDomoticzSensorType(event);
case SENSOR_TYPE_WIND: // WindDir in degrees; WindDir as text; Wind speed average ; Wind speed gust
values = formatUserVar(event, 0);
values += ";";
values += getBearing(int(UserVar[event->BaseVarIndex] / 22.5));
values += ";";
// Domoticz expects the wind speed in (m/s * 10)
values += toString((UserVar[event->BaseVarIndex + 1] * 10),ExtraTaskSettings.TaskDeviceValueDecimals[1]);
values += ";";
values += toString((UserVar[event->BaseVarIndex + 2] * 10),ExtraTaskSettings.TaskDeviceValueDecimals[2]);
values += ";0;0";
root[F("svalue")] = values.c_str();
// values.toCharArray(str, 80);
// root["svalue"] = str;
break;
}
@@ -189,9 +249,15 @@ boolean CPlugin_002(byte function, struct EventStruct *event, String& string)
addLog(LOG_LEVEL_DEBUG, log);
String pubname = ControllerSettings.Publish;
parseControllerVariables(pubname, event, false);
if (!MQTTpublish(event->ControllerIndex, pubname.c_str(), json.c_str(), Settings.MQTTRetainFlag))
pubname.replace(F("%sysname%"), Settings.Name);
pubname.replace(F("%tskname%"), ExtraTaskSettings.TaskDeviceName);
pubname.replace(F("%id%"), String(event->idx));
if (!MQTTclient.publish(pubname.c_str(), json.c_str(), Settings.MQTTRetainFlag))
{
log = F("MQTT : publish failed");
addLog(LOG_LEVEL_DEBUG, log);
MQTTConnect();
connectionFailures++;
}
else if (connectionFailures)
+5 -5
View File
@@ -57,8 +57,8 @@ boolean CPlugin_003(byte function, struct EventStruct *event, String& string)
url += formatUserVar(event, 0);
url += "\n";
// strcpy_P(log, PSTR("TELNT: Sending enter"));
// addLog(LOG_LEVEL_ERROR, log);
strcpy_P(log, PSTR("TELNT: Sending enter"));
addLog(LOG_LEVEL_ERROR, log);
client.print(" \n");
unsigned long timer = millis() + 200;
@@ -77,20 +77,20 @@ boolean CPlugin_003(byte function, struct EventStruct *event, String& string)
{
success = true;
strcpy_P(log, PSTR("TELNT: Password request ok"));
addLog(LOG_LEVEL_DEBUG, log);
addLog(LOG_LEVEL_ERROR, log);
}
delay(1);
}
strcpy_P(log, PSTR("TELNT: Sending pw"));
addLog(LOG_LEVEL_DEBUG, log);
addLog(LOG_LEVEL_ERROR, log);
client.println(SecuritySettings.ControllerPassword[event->ControllerIndex]);
delay(100);
while (client.available())
client.read();
strcpy_P(log, PSTR("TELNT: Sending cmd"));
addLog(LOG_LEVEL_DEBUG, log);
addLog(LOG_LEVEL_ERROR, log);
client.print(url);
delay(10);
while (client.available())
+2 -18
View File
@@ -16,7 +16,7 @@ boolean CPlugin_004(byte function, struct EventStruct *event, String& string)
{
Protocol[++protocolCount].Number = CPLUGIN_ID_004;
Protocol[protocolCount].usesMQTT = false;
Protocol[protocolCount].usesAccount = true;
Protocol[protocolCount].usesAccount = false;
Protocol[protocolCount].usesPassword = true;
Protocol[protocolCount].defaultPort = 80;
Protocol[protocolCount].usesID = true;
@@ -29,22 +29,6 @@ boolean CPlugin_004(byte function, struct EventStruct *event, String& string)
break;
}
case CPLUGIN_GET_PROTOCOL_DISPLAY_NAME:
{
success = true;
switch (event->idx) {
case CONTROLLER_USER:
string = F("ThingHTTP Name");
break;
case CONTROLLER_PASS:
string = F("API Key");
break;
default:
success = false;
break;
}
}
case CPLUGIN_PROTOCOL_SEND:
{
ControllerSettingsStruct ControllerSettings;
@@ -110,7 +94,7 @@ boolean CPlugin_004(byte function, struct EventStruct *event, String& string)
addLog(LOG_LEVEL_DEBUG_MORE, log);
if (line.substring(0, 15) == F("HTTP/1.1 200 OK"))
{
strcpy_P(log, PSTR("HTTP : Succes!"));
strcpy_P(log, PSTR("HTTP : Success!"));
addLog(LOG_LEVEL_DEBUG, log);
success = true;
}
+43 -40
View File
@@ -39,50 +39,51 @@ boolean CPlugin_005(byte function, struct EventStruct *event, String& string)
case CPLUGIN_PROTOCOL_RECV:
{
byte ControllerID = findFirstEnabledControllerWithId(CPLUGIN_ID_005);
if (ControllerID == CONTROLLER_MAX) {
// Controller is not enabled.
break;
} else {
String cmd;
struct EventStruct TempEvent;
bool validTopic = false;
const int lastindex = event->String1.lastIndexOf('/');
const String lastPartTopic = event->String1.substring(lastindex + 1);
if (lastPartTopic == F("cmd")) {
cmd = event->String2;
parseCommandString(&TempEvent, cmd);
TempEvent.Source = VALUE_SOURCE_MQTT;
validTopic = true;
} else {
if (lastindex > 0) {
// Topic has at least one separator
if (isFloat(event->String2) && isInt(lastPartTopic)) {
int prevLastindex = event->String1.lastIndexOf('/', lastindex - 1);
cmd = event->String1.substring(prevLastindex + 1, lastindex);
TempEvent.Par1 = lastPartTopic.toInt();
TempEvent.Par2 = event->String2.toFloat();
TempEvent.Par3 = 0;
validTopic = true;
}
}
}
if (validTopic) {
// in case of event, store to buffer and return...
String command = parseString(cmd, 1);
if (command == F("event")) {
eventBuffer = cmd.substring(6);
} else if (!PluginCall(PLUGIN_WRITE, &TempEvent, cmd)) {
remoteConfig(&TempEvent, cmd);
}
}
// Split topic into array
String tmpTopic = event->String1.substring(1);
String topicSplit[10];
int SlashIndex = tmpTopic.indexOf('/');
byte count = 0;
while (SlashIndex > 0 && count < 10 - 1)
{
topicSplit[count] = tmpTopic.substring(0, SlashIndex);
tmpTopic = tmpTopic.substring(SlashIndex + 1);
SlashIndex = tmpTopic.indexOf('/');
count++;
}
topicSplit[count] = tmpTopic;
String cmd = "";
struct EventStruct TempEvent;
if (topicSplit[count] == F("cmd"))
{
cmd = event->String2;
parseCommandString(&TempEvent, cmd);
TempEvent.Source = VALUE_SOURCE_MQTT;
}
else
{
cmd = topicSplit[count - 1];
TempEvent.Par1 = topicSplit[count].toInt();
TempEvent.Par2 = event->String2.toFloat();
TempEvent.Par3 = 0;
}
// in case of event, store to buffer and return...
String command = parseString(cmd, 1);
if (command == F("event"))
eventBuffer = cmd.substring(6);
else if
(PluginCall(PLUGIN_WRITE, &TempEvent, cmd));
else
remoteConfig(&TempEvent, cmd);
break;
}
case CPLUGIN_PROTOCOL_SEND:
{
if (!WiFiConnected(100)) {
if (WiFi.status() != WL_CONNECTED) {
success = false;
break;
}
@@ -95,7 +96,9 @@ boolean CPlugin_005(byte function, struct EventStruct *event, String& string)
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString);
String pubname = ControllerSettings.Publish;
parseControllerVariables(pubname, event, false);
pubname.replace(F("%sysname%"), Settings.Name);
pubname.replace(F("%tskname%"), ExtraTaskSettings.TaskDeviceName);
pubname.replace(F("%id%"), String(event->idx));
String value = "";
// byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[event->TaskIndex]);
@@ -108,7 +111,7 @@ boolean CPlugin_005(byte function, struct EventStruct *event, String& string)
value = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
else
value = formatUserVar(event, x);
MQTTpublish(event->ControllerIndex, tmppubname.c_str(), value.c_str(), Settings.MQTTRetainFlag);
MQTTclient.publish(tmppubname.c_str(), value.c_str(), Settings.MQTTRetainFlag);
String log = F("MQTT : ");
log += tmppubname;
log += " ";
+5 -3
View File
@@ -76,7 +76,7 @@ boolean CPlugin_006(byte function, struct EventStruct *event, String& string)
case CPLUGIN_PROTOCOL_SEND:
{
if (!WiFiConnected(100)) {
if (WiFi.status() != WL_CONNECTED) {
success = false;
break;
}
@@ -89,7 +89,9 @@ boolean CPlugin_006(byte function, struct EventStruct *event, String& string)
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString);
String pubname = ControllerSettings.Publish;
parseControllerVariables(pubname, event, false);
pubname.replace(F("%sysname%"), Settings.Name);
pubname.replace(F("%tskname%"), ExtraTaskSettings.TaskDeviceName);
pubname.replace(F("%id%"), String(event->idx));
String value = "";
// byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[event->TaskIndex]);
@@ -102,7 +104,7 @@ boolean CPlugin_006(byte function, struct EventStruct *event, String& string)
value = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
else
value = formatUserVar(event, x);
MQTTpublish(event->ControllerIndex, tmppubname.c_str(), value.c_str(), Settings.MQTTRetainFlag);
MQTTclient.publish(tmppubname.c_str(), value.c_str(), Settings.MQTTRetainFlag);
}
break;
}
+42 -15
View File
@@ -31,16 +31,10 @@ boolean CPlugin_007(byte function, struct EventStruct *event, String& string)
case CPLUGIN_PROTOCOL_SEND:
{
if (!WiFiConnected(100)) {
if (WiFi.status() != WL_CONNECTED) {
success = false;
break;
}
const byte valueCount = getValueCountFromSensorType(event->sensorType);
if (valueCount == 0 || valueCount > 3) {
addLog(LOG_LEVEL_ERROR, F("emoncms : Unknown sensortype or too many sensor values"));
break;
}
ControllerSettingsStruct ControllerSettings;
LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
@@ -65,14 +59,47 @@ boolean CPlugin_007(byte function, struct EventStruct *event, String& string)
postDataStr += Settings.Unit;
postDataStr += F("&json=");
for (byte i = 0; i < valueCount; ++i) {
postDataStr += (i == 0) ? F("{") : F(",");
postDataStr += F("field");
postDataStr += event->idx + i;
postDataStr += ":";
postDataStr += formatUserVar(event, i);
switch (event->sensorType)
{
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
postDataStr += F("{field");
postDataStr += event->idx;
postDataStr += ":";
postDataStr += formatUserVar(event, 0);
postDataStr += "}";
break;
case SENSOR_TYPE_TEMP_HUM: // dual value
case SENSOR_TYPE_TEMP_BARO:
case SENSOR_TYPE_DUAL:
postDataStr += F("{field");
postDataStr += event->idx;
postDataStr += ":";
postDataStr += formatUserVar(event, 0);
postDataStr += F(",field");
postDataStr += event->idx + 1;
postDataStr += ":";
postDataStr += formatUserVar(event, 1);
postDataStr += "}";
break;
case SENSOR_TYPE_TEMP_HUM_BARO:
case SENSOR_TYPE_TRIPLE:
postDataStr += F("{field");
postDataStr += event->idx;
postDataStr += ":";
postDataStr += formatUserVar(event, 0);
postDataStr += F(",field");
postDataStr += event->idx + 1;
postDataStr += ":";
postDataStr += formatUserVar(event, 1);
postDataStr += F(",field");
postDataStr += event->idx + 2;
postDataStr += ":";
postDataStr += formatUserVar(event, 2);
postDataStr += "}";
break;
case SENSOR_TYPE_SWITCH:
break;
}
postDataStr += "}";
postDataStr += F("&apikey=");
postDataStr += SecuritySettings.ControllerPassword[event->ControllerIndex]; // "0UDNN17RW6XAS2E5" // api key
@@ -105,7 +132,7 @@ boolean CPlugin_007(byte function, struct EventStruct *event, String& string)
addLog(LOG_LEVEL_DEBUG_MORE, log);
if (line.substring(0, 15) == F("HTTP/1.1 200 OK"))
{
strcpy_P(log, PSTR("HTTP : Succes!"));
strcpy_P(log, PSTR("HTTP : Success!"));
addLog(LOG_LEVEL_DEBUG, log);
success = true;
}
+7 -5
View File
@@ -21,7 +21,7 @@ boolean CPlugin_008(byte function, struct EventStruct *event, String& string)
Protocol[protocolCount].usesAccount = true;
Protocol[protocolCount].usesPassword = true;
Protocol[protocolCount].defaultPort = 80;
Protocol[protocolCount].usesID = false;
Protocol[protocolCount].usesID = true;
break;
}
@@ -68,7 +68,7 @@ boolean CPlugin_008(byte function, struct EventStruct *event, String& string)
//********************************************************************************
boolean HTTPSend(struct EventStruct *event, byte varIndex, float value, unsigned long longValue)
{
if (!WiFiConnected(100)) {
if (WiFi.status() != WL_CONNECTED) {
return false;
}
ControllerSettingsStruct ControllerSettings;
@@ -105,8 +105,10 @@ boolean HTTPSend(struct EventStruct *event, byte varIndex, float value, unsigned
String url = "/";
url += ControllerSettings.Publish;
parseControllerVariables(url, event, true);
//TODO: move this to a generic replacement function?
url.replace(F("%sysname%"), URLEncode(Settings.Name));
url.replace(F("%tskname%"), URLEncode(ExtraTaskSettings.TaskDeviceName));
url.replace(F("%id%"), String(event->idx));
url.replace(F("%valname%"), URLEncode(ExtraTaskSettings.TaskDeviceValueNames[varIndex]));
if (longValue)
url.replace(F("%value%"), String(longValue));
@@ -135,7 +137,7 @@ boolean HTTPSend(struct EventStruct *event, byte varIndex, float value, unsigned
addLog(LOG_LEVEL_DEBUG_MORE, line);
if (line.startsWith(F("HTTP/1.1 200 OK")))
{
// strcpy_P(log, PSTR("HTTP : Succes!"));
// strcpy_P(log, PSTR("HTTP : Success!"));
// addLog(LOG_LEVEL_DEBUG, log);
addLog(LOG_LEVEL_DEBUG, F("HTTP : Success!"));
// success = true;
+2 -2
View File
@@ -20,7 +20,7 @@
- moved on/off translation for SENSOR_TYPE_SWITCH/DIMMER to FHEM module
- v1.03
- changed http request from GET to POST (RFC conform)
- removed obsolet http get url code
- removed obsolete http get url code
- v1.04
- added build options and node_type_id to JSON/device
/******************************************************************************/
@@ -56,7 +56,7 @@ boolean CPlugin_009(byte function, struct EventStruct *event, String& string)
case CPLUGIN_PROTOCOL_SEND:
{
if (!WiFiConnected(100)) {
if (WiFi.status() != WL_CONNECTED) {
success = false;
break;
}
+3 -1
View File
@@ -80,7 +80,9 @@ void C010_Send(struct EventStruct *event, byte varIndex, float value, unsigned l
String msg = "";
msg += ControllerSettings.Publish;
parseControllerVariables(msg, event, false);
msg.replace(F("%sysname%"), Settings.Name);
msg.replace(F("%tskname%"), ExtraTaskSettings.TaskDeviceName);
msg.replace(F("%id%"), String(event->idx));
msg.replace(F("%valname%"), ExtraTaskSettings.TaskDeviceValueNames[varIndex]);
if (longValue)
msg.replace(F("%value%"), String(longValue));
+65 -4
View File
@@ -120,7 +120,7 @@ boolean CPlugin_011(byte function, struct EventStruct *event, String& string)
//********************************************************************************
boolean HTTPSend011(struct EventStruct *event)
{
if (!WiFiConnected(100)) {
if (WiFi.status() != WL_CONNECTED) {
return false;
}
ControllerSettingsStruct ControllerSettings;
@@ -270,14 +270,75 @@ void ReplaceTokenByValue(String& s, struct EventStruct *event)
// %1%%vname1%,Standort=%tskname% Wert=%val1%%/1%%2%%LF%%vname2%,Standort=%tskname% Wert=%val2%%/2%%3%%LF%%vname3%,Standort=%tskname% Wert=%val3%%/3%%4%%LF%%vname4%,Standort=%tskname% Wert=%val4%%/4%
addLog(LOG_LEVEL_DEBUG_MORE, F("HTTP before parsing: "));
addLog(LOG_LEVEL_DEBUG_MORE, s);
const byte valueCount = getValueCountFromSensorType(event->sensorType);
DeleteNotNeededValues(s,valueCount);
switch (event->sensorType)
{
case SENSOR_TYPE_SINGLE:
case SENSOR_TYPE_SWITCH:
case SENSOR_TYPE_DIMMER:
case SENSOR_TYPE_WIND:
case SENSOR_TYPE_LONG:
{
DeleteNotNeededValues(s,1);
break;
}
case SENSOR_TYPE_DUAL:
case SENSOR_TYPE_TEMP_HUM:
case SENSOR_TYPE_TEMP_BARO:
{
DeleteNotNeededValues(s,2);
break;
}
case SENSOR_TYPE_TRIPLE:
case SENSOR_TYPE_TEMP_HUM_BARO:
{
DeleteNotNeededValues(s,3);
break;
}
case SENSOR_TYPE_QUAD:
{
DeleteNotNeededValues(s,4);
break;
}
}
addLog(LOG_LEVEL_DEBUG_MORE, F("HTTP after parsing: "));
addLog(LOG_LEVEL_DEBUG_MORE, s);
parseControllerVariables(s, event, true);
//NOTE: cant we just call parseTemplate() for all the standard stuff??
s.replace(F("%systime%"), getTimeString(':'));
#if FEATURE_ADC_VCC
s.replace(F("%vcc%"), String(vcc));
#endif
// IPAddress ip = WiFi.localIP();
// char strIP[20];
// sprintf_P(strIP, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]);
s.replace(F("%ip%"),WiFi.localIP().toString());
s.replace(F("%sysload%"), String(100 - (100 * loopCounterLast / loopCounterMax)));
s.replace(F("%uptime%"), String(wdcounter / 2));
s.replace(F("%CR%"), F("\r"));
s.replace(F("%LF%"), F("\n"));
s.replace(F("%sysname%"), URLEncode(Settings.Name));
s.replace(F("%tskname%"), URLEncode(ExtraTaskSettings.TaskDeviceName));
s.replace(F("%id%"), String(event->idx));
s.replace(F("%vname1%"), URLEncode(ExtraTaskSettings.TaskDeviceValueNames[0]));
s.replace(F("%vname2%"), URLEncode(ExtraTaskSettings.TaskDeviceValueNames[1]));
s.replace(F("%vname3%"), URLEncode(ExtraTaskSettings.TaskDeviceValueNames[2]));
s.replace(F("%vname4%"), URLEncode(ExtraTaskSettings.TaskDeviceValueNames[3]));
if (event->sensorType == SENSOR_TYPE_LONG)
s.replace(F("%val1%"), String((unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16)));
else {
s.replace(F("%val1%"), formatUserVar(event, 0));
s.replace(F("%val2%"), formatUserVar(event, 1));
s.replace(F("%val3%"), formatUserVar(event, 2));
s.replace(F("%val4%"), formatUserVar(event, 3));
}
addLog(LOG_LEVEL_DEBUG_MORE, F("HTTP after replacements: "));
addLog(LOG_LEVEL_DEBUG_MORE, s);
}
-149
View File
@@ -1,149 +0,0 @@
//#######################################################################################################
//########################### Controller Plugin 012: Blynk #############################################
//#######################################################################################################
#ifdef PLUGIN_BUILD_TESTING
#define CPLUGIN_012
#define CPLUGIN_ID_012 12
#define CPLUGIN_NAME_012 "Blynk HTTP [TESTING]"
boolean CPlugin_012(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case CPLUGIN_PROTOCOL_ADD:
{
Protocol[++protocolCount].Number = CPLUGIN_ID_012;
Protocol[protocolCount].usesMQTT = false;
Protocol[protocolCount].usesAccount = false;
Protocol[protocolCount].usesPassword = true;
Protocol[protocolCount].defaultPort = 80;
Protocol[protocolCount].usesID = true;
break;
}
case CPLUGIN_GET_DEVICENAME:
{
string = F(CPLUGIN_NAME_012);
break;
}
case CPLUGIN_PROTOCOL_SEND:
{
if (WiFi.status() != WL_CONNECTED) {
success = false;
break;
}
String postDataStr = F("");
const byte valueCount = getValueCountFromSensorType(event->sensorType);
success = CPlugin_012_send(event, valueCount);
break;
}
}
return success;
}
boolean CPlugin_012_send(struct EventStruct *event, int nrValues) {
String postDataStr = F("");
boolean success = true;
for (int i = 0; i < nrValues && success; ++i) {
postDataStr = F("update/V") ;
postDataStr += event->idx + i;
postDataStr += F("?value=");
postDataStr += formatUserVar(event, i);
success = Blynk_get(postDataStr, event->ControllerIndex);
}
return success;
}
boolean Blynk_get(const String& command, byte controllerIndex, float *data )
{
if (WiFi.status() != WL_CONNECTED) {
return false;
}
ControllerSettingsStruct ControllerSettings;
LoadControllerSettings(controllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
// Use WiFiClient class to create TCP connections
WiFiClient client;
if ((SecuritySettings.ControllerPassword[controllerIndex][0] == 0) || !ControllerSettings.connectToHost(client))
{
connectionFailures++;
addLog(LOG_LEVEL_ERROR, F("Blynk : connection failed"));
return false;
}
if (connectionFailures)
connectionFailures--;
// We now create a URI for the request
char request[300] = {0};
sprintf_P(request,
PSTR("GET /%s/%s HTTP/1.1\r\n Host: %s \r\n Connection: close\r\n\r\n"),
SecuritySettings.ControllerPassword[controllerIndex],
command.c_str(),
ControllerSettings.getHost().c_str());
addLog(LOG_LEVEL_DEBUG, request);
client.print(request);
unsigned long timer = millis() + 200;
while (!client.available() && !timeOutReached(timer))
yield();
boolean success = false;
char log[80] = {0};
// Read all the lines of the reply from server and log them
while (client.available()) {
String line;
safeReadStringUntil(client, line, '\n');
addLog(LOG_LEVEL_DEBUG_MORE, line);
// success ?
if (line.substring(0, 15) == "HTTP/1.1 200 OK") {
strcpy_P(log, PSTR("HTTP : Success"));
success = true;
}
else if (line.substring(0, 24) == "HTTP/1.1 400 Bad Request") {
strcpy_P(log, PSTR("HTTP : Unauthorized"));
}
else if (line.substring(0, 25) == "HTTP/1.1 401 Unauthorized") {
strcpy_P(log, PSTR("HTTP : Unauthorized"));
}
addLog(LOG_LEVEL_DEBUG, log);
// data only
if (data && line.startsWith("["))
{
String strValue = line;
byte pos = strValue.indexOf('"',2);
strValue = strValue.substring(2, pos);
strValue.trim();
float value = strValue.toFloat();
*data = value;
success = true;
char value_char[5] = {0};
strValue.toCharArray(value_char, 5);
sprintf_P(log, PSTR("Blynk get - %s => %s"),command.c_str(), value_char );
addLog(LOG_LEVEL_DEBUG, log);
}
yield();
}
strcpy_P(log, PSTR("HTTP : closing connection"));
addLog(LOG_LEVEL_DEBUG, log);
client.flush();
client.stop();
// important - backgroudtasks - free mem
timer = millis() + Settings.MessageDelay;
while (!timeOutReached(timer))
backgroundtasks();
return success;
}
#endif
-265
View File
@@ -1,265 +0,0 @@
//#######################################################################################################
//########################### Controller Plugin 013: ESPEasy P2P network ################################
//#######################################################################################################
#define CPLUGIN_013
#define CPLUGIN_ID_013 13
#define CPLUGIN_NAME_013 "ESPEasy P2P Networking"
WiFiUDP C013_portUDP;
struct infoStruct
{
byte header = 255;
byte ID = 3;
byte sourcelUnit;
byte destUnit;
byte sourceTaskIndex;
byte destTaskIndex;
byte deviceNumber;
char taskName[26];
char ValueNames[VARS_PER_TASK][26];
};
struct dataStruct
{
byte header = 255;
byte ID = 5;
byte sourcelUnit;
byte destUnit;
byte sourceTaskIndex;
byte destTaskIndex;
float Values[VARS_PER_TASK];
};
boolean CPlugin_013(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case CPLUGIN_PROTOCOL_ADD:
{
Protocol[++protocolCount].Number = CPLUGIN_ID_013;
Protocol[protocolCount].usesMQTT = false;
Protocol[protocolCount].usesTemplate = false;
Protocol[protocolCount].usesAccount = false;
Protocol[protocolCount].usesPassword = false;
Protocol[protocolCount].defaultPort = 65501;
Protocol[protocolCount].usesID = false;
Protocol[protocolCount].Custom = true;
break;
}
case CPLUGIN_GET_DEVICENAME:
{
string = F(CPLUGIN_NAME_013);
break;
}
case CPLUGIN_PROTOCOL_TEMPLATE:
{
event->String1 = "";
event->String2 = "";
break;
}
case CPLUGIN_INIT:
{
//C013_portUDP.begin(Settings.UDPPort);
break;
}
case CPLUGIN_TASK_CHANGE_NOTIFICATION:
{
C013_SendUDPTaskInfo(0, event->TaskIndex, event->TaskIndex);
break;
}
case CPLUGIN_PROTOCOL_SEND:
{
C013_Send(event, 0, UserVar[event->BaseVarIndex], 0);
break;
}
case CPLUGIN_UDP_IN:
{
C013_Receive(event);
break;
}
}
return success;
}
//********************************************************************************
// Generic UDP message
//********************************************************************************
void C013_Send(struct EventStruct *event, byte varIndex, float value, unsigned long longValue)
{
ControllerSettingsStruct ControllerSettings;
LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
statusLED(true);
C013_SendUDPTaskData(0, event->TaskIndex, event->TaskIndex);
}
void C013_SendUDPTaskInfo(byte destUnit, byte sourceTaskIndex, byte destTaskIndex)
{
if (!WiFiConnected(100)) {
return;
}
struct infoStruct infoReply;
infoReply.sourcelUnit = Settings.Unit;
infoReply.sourceTaskIndex = sourceTaskIndex;
infoReply.destTaskIndex = destTaskIndex;
LoadTaskSettings(infoReply.sourceTaskIndex);
infoReply.deviceNumber = Settings.TaskDeviceNumber[infoReply.sourceTaskIndex];
strcpy(infoReply.taskName, ExtraTaskSettings.TaskDeviceName);
for (byte x = 0; x < VARS_PER_TASK; x++)
strcpy(infoReply.ValueNames[x], ExtraTaskSettings.TaskDeviceValueNames[x]);
byte firstUnit = 1;
byte lastUnit = UNIT_MAX - 1;
if (destUnit != 0)
{
firstUnit = destUnit;
lastUnit = destUnit;
}
for (byte x = firstUnit; x <= lastUnit; x++)
{
if (x != Settings.Unit){
infoReply.destUnit = x;
C013_sendUDP(x, (byte*)&infoReply, sizeof(infoStruct));
delay(10);
}
}
delay(50);
}
void C013_SendUDPTaskData(byte destUnit, byte sourceTaskIndex, byte destTaskIndex)
{
if (!WiFiConnected(100)) {
return;
}
struct dataStruct dataReply;
dataReply.sourcelUnit = Settings.Unit;
dataReply.sourceTaskIndex = sourceTaskIndex;
dataReply.destTaskIndex = destTaskIndex;
for (byte x = 0; x < VARS_PER_TASK; x++)
dataReply.Values[x] = UserVar[dataReply.sourceTaskIndex * VARS_PER_TASK + x];
byte firstUnit = 1;
byte lastUnit = UNIT_MAX - 1;
if (destUnit != 0)
{
firstUnit = destUnit;
lastUnit = destUnit;
}
for (byte x = firstUnit; x <= lastUnit; x++)
{
if (x != Settings.Unit){
dataReply.destUnit = x;
C013_sendUDP(x, (byte*) &dataReply, sizeof(dataStruct));
delay(10);
}
}
delay(50);
}
/*********************************************************************************************\
Send UDP message (unit 255=broadcast)
\*********************************************************************************************/
void C013_sendUDP(byte unit, byte* data, byte size)
{
if (!WiFiConnected(100)) {
return;
}
if (unit != 255)
if (Nodes[unit].ip[0] == 0)
return;
String log = "C013 : Send UDP message to ";
log += unit;
addLog(LOG_LEVEL_DEBUG_MORE, log);
statusLED(true);
IPAddress remoteNodeIP;
if (unit == 255)
remoteNodeIP = {255, 255, 255, 255};
else
remoteNodeIP = Nodes[unit].ip;
C013_portUDP.beginPacket(remoteNodeIP, Settings.UDPPort);
C013_portUDP.write(data, size);
C013_portUDP.endPacket();
}
void C013_Receive(struct EventStruct *event) {
if (event->Data[1] > 1 && event->Data[1] < 6)
{
String log = (F("C013 : msg "));
for (byte x = 1; x < 6; x++)
{
log += " ";
log += (int)event->Data[x];
}
addLog(LOG_LEVEL_DEBUG_MORE, log);
}
switch (event->Data[1]) {
case 2: // sensor info pull request
{
//SendUDPTaskInfo(packetBuffer[2], packetBuffer[5], packetBuffer[4]);
break;
}
case 3: // sensor info
{
struct infoStruct infoReply;
memcpy((byte*)&infoReply, (byte*)event->Data, sizeof(infoStruct));
// to prevent flash wear out (bugs in communication?) we can only write to an empty task
// so it will write only once and has to be cleared manually through webgui
if (Settings.TaskDeviceNumber[infoReply.destTaskIndex] == 0)
{
Settings.TaskDeviceNumber[infoReply.destTaskIndex] = infoReply.deviceNumber;
Settings.TaskDeviceDataFeed[infoReply.destTaskIndex] = 1; // remote feed
for (byte x = 0; x < CONTROLLER_MAX; x++)
Settings.TaskDeviceSendData[x][infoReply.destTaskIndex] = false;
strcpy(ExtraTaskSettings.TaskDeviceName, infoReply.taskName);
for (byte x = 0; x < VARS_PER_TASK; x++)
strcpy( ExtraTaskSettings.TaskDeviceValueNames[x], infoReply.ValueNames[x]);
SaveTaskSettings(infoReply.destTaskIndex);
SaveSettings();
}
break;
}
case 4: // sensor data pull request
{
//SendUDPTaskData(packetBuffer[2], packetBuffer[5], packetBuffer[4]);
break;
}
case 5: // sensor data
{
struct dataStruct dataReply;
memcpy((byte*)&dataReply, (byte*)event->Data, sizeof(dataStruct));
// only if this task has a remote feed, update values
if (Settings.TaskDeviceDataFeed[dataReply.destTaskIndex] != 0)
{
for (byte x = 0; x < VARS_PER_TASK; x++)
{
UserVar[dataReply.destTaskIndex * VARS_PER_TASK + x] = dataReply.Values[x];
}
if (Settings.UseRules)
createRuleEvents(dataReply.destTaskIndex);
}
break;
}
}
}
-140
View File
@@ -1,140 +0,0 @@
// HUM_STAT can be one of:
// 0=Normal
// 1=Comfortable
// 2=Dry
// 3=Wet
String humStatDomoticz(struct EventStruct *event, byte rel_index){
const int hum = UserVar[event->BaseVarIndex + rel_index];
if (hum < 30) { return formatUserVarDomoticz(2); }
if (hum < 40) { return formatUserVarDomoticz(0); }
if (hum < 59) { return formatUserVarDomoticz(1); }
return formatUserVarDomoticz(3);
}
int mapRSSItoDomoticz() {
long rssi = WiFi.RSSI();
if (-50 < rssi) { return 10; }
if (rssi <= -98) { return 0; }
rssi = rssi + 97; // Range 0..47 => 1..9
return (rssi / 5) + 1;
}
int mapVccToDomoticz() {
#if FEATURE_ADC_VCC
// Voltage range from 2.6V .. 3.6V => 0..100%
if (vcc < 2.6) return 0;
return (vcc - 2.6) * 100;
#else
return 255;
#endif
}
// Format including trailing semi colon
String formatUserVarDomoticz(struct EventStruct *event, byte rel_index) {
String text = formatUserVar(event, rel_index);
text += F(";");
return text;
}
String formatUserVarDomoticz(int value) {
String text;
text += value;
text.trim();
text += F(";");
return text;
}
String formatDomoticzSensorType(struct EventStruct *event) {
String values;
switch (event->sensorType)
{
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
values = formatUserVarDomoticz(event, 0);
break;
case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags)
values = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
break;
case SENSOR_TYPE_DUAL: // any sensor that uses two simple values
values = formatUserVarDomoticz(event, 0);
values += formatUserVarDomoticz(event, 1);
break;
case SENSOR_TYPE_TEMP_HUM:
// temp + hum + hum_stat, used for DHT11
// http://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s#Temperature.2Fhumidity
values = formatUserVarDomoticz(event, 0); // TEMP = Temperature
values += formatUserVarDomoticz(event, 1); // HUM = Humidity
values += humStatDomoticz(event, 1); // HUM_STAT = Humidity status
break;
case SENSOR_TYPE_TEMP_HUM_BARO:
// temp + hum + hum_stat + bar + bar_fore, used for BME280
// http://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s#Temperature.2Fhumidity.2Fbarometer
values = formatUserVarDomoticz(event, 0); // TEMP = Temperature
values += formatUserVarDomoticz(event, 1); // HUM = Humidity
values += humStatDomoticz(event, 1); // HUM_STAT = Humidity status
values += formatUserVarDomoticz(event, 2); // BAR = Barometric pressure
values += formatUserVarDomoticz(0); // BAR_FOR = Barometer forecast
break;
case SENSOR_TYPE_TEMP_BARO:
// temp + hum + hum_stat + bar + bar_fore, used for BMP085
// http://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s#Temperature.2Fbarometer
values = formatUserVarDomoticz(event, 0); // TEMP = Temperature
values += formatUserVarDomoticz(event, 1); // BAR = Barometric pressure
values += formatUserVarDomoticz(0); // BAR_FOR = Barometer forecast
values += formatUserVarDomoticz(0); // ALTITUDE= Not used at the moment, can be 0
break;
case SENSOR_TYPE_TRIPLE:
values = formatUserVarDomoticz(event, 0);
values += formatUserVarDomoticz(event, 1);
values += formatUserVarDomoticz(event, 2);
break;
case SENSOR_TYPE_QUAD:
values = formatUserVarDomoticz(event, 0);
values += formatUserVarDomoticz(event, 1);
values += formatUserVarDomoticz(event, 2);
values += formatUserVarDomoticz(event, 3);
break;
case SENSOR_TYPE_WIND:
// WindDir in degrees; WindDir as text; Wind speed average ; Wind speed gust; 0
// http://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s#Wind
values = formatUserVarDomoticz(event, 0); // WB = Wind bearing (0-359)
values += getBearing(UserVar[event->BaseVarIndex]); // WD = Wind direction (S, SW, NNW, etc.)
values += ";"; // Needed after getBearing
// Domoticz expects the wind speed in (m/s * 10)
values += toString((UserVar[event->BaseVarIndex + 1] * 10),ExtraTaskSettings.TaskDeviceValueDecimals[1]);
values += ";"; // WS = 10 * Wind speed [m/s]
values += toString((UserVar[event->BaseVarIndex + 2] * 10),ExtraTaskSettings.TaskDeviceValueDecimals[2]);
values += ";"; // WG = 10 * Gust [m/s]
values += formatUserVarDomoticz(0); // Temperature
values += formatUserVarDomoticz(0); // Temperature Windchill
break;
case SENSOR_TYPE_SWITCH:
case SENSOR_TYPE_DIMMER:
// Too specific for HTTP/MQTT
break;
default:
{
String log = F("Domoticz Controller: Not yet implemented sensor type: ");
log += event->sensorType;
log += F(" idx: ");
log += event->idx;
addLog(LOG_LEVEL_ERROR, log);
break;
}
}
// Now strip trailing semi colon.
int index_last_char = values.length() -1;
if (index_last_char > 0 && values.charAt(index_last_char) == ';') {
values.setCharAt(index_last_char, ' ');
}
values.trim();
{
String log = F(" Domoticz: Sensortype: ");
log += event->sensorType;
log += F(" idx: ");
log += event->idx;
log += F(" values: ");
log += values;
addLog(LOG_LEVEL_INFO, log);
}
return values;
}
-28
View File
@@ -1,28 +0,0 @@
/*********************************************************************************************\
Get value count from sensor type
\*********************************************************************************************/
byte getValueCountFromSensorType(byte sensorType)
{
switch (sensorType)
{
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
case SENSOR_TYPE_SWITCH:
case SENSOR_TYPE_DIMMER:
return 1;
case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags)
return 1;
case SENSOR_TYPE_TEMP_HUM:
case SENSOR_TYPE_TEMP_BARO:
case SENSOR_TYPE_DUAL:
return 2;
case SENSOR_TYPE_TEMP_HUM_BARO:
case SENSOR_TYPE_TRIPLE:
case SENSOR_TYPE_WIND:
return 3;
case SENSOR_TYPE_QUAD:
return 4;
}
addLog(LOG_LEVEL_ERROR, F("getValueCountFromSensorType: Unknown sensortype"));
return 0;
}
+25 -54
View File
@@ -6,7 +6,7 @@
#define NPLUGIN_ID_001 1
#define NPLUGIN_NAME_001 "Email (SMTP)"
#define NPLUGIN_001_TIMEOUT 5000
#define NPLUGIN_001_TIMEOUT 3000
boolean NPlugin_001(byte function, struct EventStruct *event, String& string)
{
@@ -56,7 +56,7 @@ boolean NPlugin_001(byte function, struct EventStruct *event, String& string)
body = NotificationSettings.Body;
subject = parseTemplate(subject, subject.length());
body = parseTemplate(body, body.length());
NPlugin_001_send(NotificationSettings, subject, body);
NPlugin_001_send(NotificationSettings.Domain, NotificationSettings.Receiver, NotificationSettings.Sender, subject, body, NotificationSettings.Server, NotificationSettings.Port);
success = true;
}
@@ -64,46 +64,29 @@ boolean NPlugin_001(byte function, struct EventStruct *event, String& string)
return success;
}
boolean NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, const String& aSub, const String& aMesg) {
// String& aDomain , String aTo, String aFrom, String aSub, String aMesg, String aHost, int aPort)
boolean NPlugin_001_send(String aDomain , String aTo, String aFrom, String aSub, String aMesg, String aHost, int aPort)
{
boolean myStatus = false;
// Use WiFiClient class to create TCP connections
WiFiClient client;
String aHost = notificationsettings.Server;
addLog(LOG_LEVEL_DEBUG, String(F("EMAIL: Connecting to "))+aHost + notificationsettings.Port);
if (!client.connect(aHost.c_str(), notificationsettings.Port)) {
addLog(LOG_LEVEL_ERROR, String(F("EMAIL: Error connecting to "))+aHost + notificationsettings.Port);
addLog(LOG_LEVEL_DEBUG, String(F("EMAIL: Connecting to "))+aHost);
if (!client.connect(aHost.c_str(), aPort)) {
addLog(LOG_LEVEL_ERROR, String(F("EMAIL: Error connecting to "))+aHost);
myStatus = false;
}
else {
String mailheader = F(
"From: $nodename <$emailfrom>\r\n"
"To: $ato\r\n"
"Subject: $subject\r\n"
"Reply-To: $nodename <$emailfrom>\r\n"
"MIME-VERSION: 1.0\r\n"
"Content-type: text/html; charset=UTF-8\r\n"
"X-Mailer: EspEasy v$espeasyversion\r\n\r\n"
);
mailheader.replace(String(F("$nodename")), Settings.Name);
mailheader.replace(String(F("$emailfrom")), notificationsettings.Sender);
mailheader.replace(String(F("$ato")), notificationsettings.Receiver);
mailheader.replace(String(F("$subject")), aSub);
mailheader.replace(String(F("$espeasyversion")), String(BUILD));
// Wait for Client to Start Sending
// The MTA Exchange
while (true) {
if (!NPlugin_001_MTA(client, "", F("220 "))) break;
if (!NPlugin_001_MTA(client, String(F("EHLO ")) + notificationsettings.Domain, F("250 "))) break;
if (!NPlugin_001_Auth(client, notificationsettings.User, notificationsettings.Pass)) break;
if (!NPlugin_001_MTA(client, String(F("MAIL FROM:")) + notificationsettings.Sender + "", F("250 "))) break;
if (!NPlugin_001_MTA(client, String(F("RCPT TO:")) + notificationsettings.Receiver + "", F("250 "))) break;
if (!NPlugin_001_MTA(client, F("DATA"), F("354 "))) break;
if (!NPlugin_001_MTA(client, mailheader + aMesg + String(F("\r\n.\r\n")), F("250 "))) break;
if (NPlugin_001_MTA(client, "", F("220 ")) == false) break;
if (NPlugin_001_MTA(client, String(F("EHLO ")) + aDomain, F("250 ")) == false) break;
if (NPlugin_001_MTA(client, String(F("MAIL FROM:")) + aFrom + "", F("250 ")) == false) break;
if (NPlugin_001_MTA(client, String(F("RCPT TO:")) + aTo + "", F("250 ")) == false) break;
if (NPlugin_001_MTA(client, F("DATA"), F("354 ")) == false) break;
if (NPlugin_001_MTA(client, String(F("Subject:")) + aSub + F("\r\n\r\n") + aMesg + F("\r\n.\r\n"), F("250 ")) == false) break;
myStatus = true;
break;
@@ -117,32 +100,21 @@ boolean NPlugin_001_send(const NotificationSettingsStruct& notificationsettings,
addLog(LOG_LEVEL_INFO, F("EMAIL: Connection Closed Successfully"));
}
else {
String log = F("EMAIL: Connection Closed With Error. Used header: ");
log += mailheader;
addLog(LOG_LEVEL_ERROR, log);
addLog(LOG_LEVEL_ERROR, F("EMAIL: Connection Closed With Error"));
}
}
return myStatus;
}
boolean NPlugin_001_Auth(WiFiClient& client, String user, String pass) {
if (user.length() == 0 || pass.length() == 0) {
// No user/password given.
return true;
}
if (!NPlugin_001_MTA(client, String(F("AUTH LOGIN")), F("334 "))) return false;
base64 encoder;
String auth;
auth = encoder.encode(user);
if (!NPlugin_001_MTA(client, auth, F("334 "))) return false;
auth = encoder.encode(pass);
if (!NPlugin_001_MTA(client, auth, F("235 "))) return false;
return true;
}
boolean NPlugin_001_MTA(WiFiClient& client, String aStr, const String &aWaitForPattern)
{
boolean myStatus = false;
addLog(LOG_LEVEL_DEBUG, aStr);
if (aStr.length() ) client.println(aStr);
@@ -153,10 +125,8 @@ boolean NPlugin_001_MTA(WiFiClient& client, String aStr, const String &aWaitForP
unsigned long timer = millis() + NPLUGIN_001_TIMEOUT;
while (true) {
if (timeOutReached(timer)) {
String log = F("Plugin_001_MTA: timeout. ");
log += aStr;
addLog(LOG_LEVEL_ERROR, log);
return false;
myStatus = false;
break;
}
yield();
@@ -168,9 +138,10 @@ boolean NPlugin_001_MTA(WiFiClient& client, String aStr, const String &aWaitForP
addLog(LOG_LEVEL_DEBUG, line);
if (line.indexOf(aWaitForPattern) >= 0) {
return true;
myStatus = true;
break;
}
}
return false;
return myStatus;
}
+1 -1
View File
@@ -45,7 +45,7 @@ boolean NPlugin_002(byte function, struct EventStruct *event, String& string)
{
NotificationSettingsStruct NotificationSettings;
LoadNotificationSettings(event->NotificationIndex, (byte*)&NotificationSettings, sizeof(NotificationSettings));
//this reserves IRAM and uninitalized RAM
//this reserves IRAM and uninitialized RAM
tone(NotificationSettings.Pin1, 500, 500);
success = true;
}
+102 -94
View File
@@ -6,25 +6,16 @@
#define PLUGIN_ID_001 1
#define PLUGIN_NAME_001 "Switch input - Switch"
#define PLUGIN_VALUENAME1_001 "Switch"
Servo servo1;
Servo servo2;
// Make sure the initial default is a switch (value 0)
#define PLUGIN_001_TYPE_SWITCH 0
#define PLUGIN_001_TYPE_DIMMER 3 // Due to some changes in previous versions, do not use 2.
#define PLUGIN_001_BUTTON_TYPE_NORMAL_SWITCH 0
#define PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_LOW 1
#define PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_HIGH 2
boolean Plugin_001_read_switch_state(struct EventStruct *event) {
return digitalRead(Settings.TaskDevicePin1[event->TaskIndex]) == HIGH;
}
#if defined(ESP8266)
Servo servo1;
Servo servo2;
#endif
boolean Plugin_001(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
static boolean switchstate[TASKS_MAX];
static boolean outputstate[TASKS_MAX];
static byte switchstate[TASKS_MAX];
static byte outputstate[TASKS_MAX];
switch (function)
{
@@ -59,27 +50,26 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
String options[2];
options[0] = F("Switch");
options[1] = F("Dimmer");
int optionValues[2] = { PLUGIN_001_TYPE_SWITCH, PLUGIN_001_TYPE_DIMMER };
const byte switchtype = P001_getSwitchType(event);
addFormSelector(string, F("Switch Type"), F("plugin_001_type"), 2, options, optionValues, switchtype);
int optionValues[2] = { 1, 2 };
addFormSelector(string, F("Switch Type"), F("plugin_001_type"), 2, options, optionValues, choice);
if (switchtype == PLUGIN_001_TYPE_DIMMER)
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2)
{
char tmpString[128];
sprintf_P(tmpString, PSTR("<TR><TD>Dim value:<TD><input type='text' name='plugin_001_dimvalue' value='%u'>"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
string += tmpString;
}
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][2];
choice = Settings.TaskDevicePluginConfig[event->TaskIndex][2];
String buttonOptions[3];
buttonOptions[0] = F("Normal Switch");
buttonOptions[1] = F("Push Button Active Low");
buttonOptions[2] = F("Push Button Active High");
int buttonOptionValues[3] = {PLUGIN_001_BUTTON_TYPE_NORMAL_SWITCH, PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_LOW, PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_HIGH};
addFormSelector(string, F("Switch Button Type"), F("plugin_001_button"), 3, buttonOptions, buttonOptionValues, choice);
addFormSelector(string, F("Switch Button Type"), F("plugin_001_button"), 3, buttonOptions, NULL, choice);
addFormCheckBox(string, F("Send Boot state"),F("plugin_001_boot"),
Settings.TaskDevicePluginConfig[event->TaskIndex][3]);
@@ -91,7 +81,7 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_001_type"));
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == PLUGIN_001_TYPE_DIMMER)
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2)
{
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_001_dimvalue"));
}
@@ -113,7 +103,7 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
setPinState(PLUGIN_ID_001, Settings.TaskDevicePin1[event->TaskIndex], PIN_MODE_INPUT, 0);
switchstate[event->TaskIndex] = Plugin_001_read_switch_state(event);
switchstate[event->TaskIndex] = digitalRead(Settings.TaskDevicePin1[event->TaskIndex]);
outputstate[event->TaskIndex] = switchstate[event->TaskIndex];
// if boot state must be send, inverse default state
@@ -128,48 +118,43 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
case PLUGIN_TEN_PER_SECOND:
{
const boolean state = Plugin_001_read_switch_state(event);
byte state = digitalRead(Settings.TaskDevicePin1[event->TaskIndex]);
if (state != switchstate[event->TaskIndex])
{
switchstate[event->TaskIndex] = state;
const boolean currentOutputState = outputstate[event->TaskIndex];
boolean new_outputState = currentOutputState;
switch(Settings.TaskDevicePluginConfig[event->TaskIndex][2]) {
case PLUGIN_001_BUTTON_TYPE_NORMAL_SWITCH:
new_outputState = state;
break;
case PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_LOW:
if (!state)
new_outputState = !currentOutputState;
break;
case PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_HIGH:
if (state)
new_outputState = !currentOutputState;
break;
byte currentOutputState = outputstate[event->TaskIndex];
if (Settings.TaskDevicePluginConfig[event->TaskIndex][2] == 0) //normal switch
outputstate[event->TaskIndex] = state;
else
{
if (Settings.TaskDevicePluginConfig[event->TaskIndex][2] == 1) // active low push button
{
if (state == 0)
outputstate[event->TaskIndex] = !outputstate[event->TaskIndex];
}
else // active high push button
{
if (state == 1)
outputstate[event->TaskIndex] = !outputstate[event->TaskIndex];
}
}
// send if output needs to be changed
if (currentOutputState != new_outputState)
if (currentOutputState != outputstate[event->TaskIndex])
{
outputstate[event->TaskIndex] = new_outputState;
boolean sendState = new_outputState;
byte sendState = outputstate[event->TaskIndex];
if (Settings.TaskDevicePin1Inversed[event->TaskIndex])
sendState = !sendState;
byte output_value = sendState ? 1 : 0;
sendState = !outputstate[event->TaskIndex];
UserVar[event->BaseVarIndex] = sendState;
event->sensorType = SENSOR_TYPE_SWITCH;
if (P001_getSwitchType(event) == PLUGIN_001_TYPE_DIMMER) {
if (sendState) {
output_value = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
// Only set type to being dimmer when setting a value else it is "switched off".
event->sensorType = SENSOR_TYPE_DIMMER;
}
if ((sendState == 1) && (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2))
{
event->sensorType = SENSOR_TYPE_DIMMER;
UserVar[event->BaseVarIndex] = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
}
UserVar[event->BaseVarIndex] = output_value;
String log = F("SW : Switch state ");
log += state ? F("1") : F("0");
log += F(" Output value ");
log += output_value;
String log = F("SW : State ");
log += sendState;
addLog(LOG_LEVEL_INFO, log);
sendData(event);
}
@@ -197,7 +182,7 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
if (command == F("gpio"))
{
success = true;
if (event->Par1 >= 0 && event->Par1 <= 16)
if (event->Par1 >= 0 && event->Par1 <= PIN_D_MAX)
{
pinMode(event->Par1, OUTPUT);
digitalWrite(event->Par1, event->Par2);
@@ -211,10 +196,11 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
if (command == F("pwm"))
{
success = true;
if (event->Par1 >= 0 && event->Par1 <= 16)
if (event->Par1 >= 0 && event->Par1 <= PIN_D_MAX)
{
pinMode(event->Par1, OUTPUT);
#if defined(ESP8266)
pinMode(event->Par1, OUTPUT);
#endif
if(event->Par3 != 0)
{
byte prev_mode;
@@ -231,12 +217,22 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
curr_value += step_value;
int16_t new_value;
new_value = (uint16_t)(curr_value >> 12);
analogWrite(event->Par1, new_value);
#if defined(ESP8266)
analogWrite(event->Par1, new_value);
#endif
#if defined(ESP32)
analogWriteESP32(event->Par1, new_value);
#endif
delay(1);
}
}
analogWrite(event->Par1, event->Par2);
#if defined(ESP8266)
analogWrite(event->Par1, event->Par2);
#endif
#if defined(ESP32)
analogWriteESP32(event->Par1, event->Par2);
#endif
setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_PWM, event->Par2);
log = String(F("SW : GPIO ")) + String(event->Par1) + String(F(" Set PWM to ")) + String(event->Par2);
addLog(LOG_LEVEL_INFO, log);
@@ -247,7 +243,7 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
if (command == F("pulse"))
{
success = true;
if (event->Par1 >= 0 && event->Par1 <= 16)
if (event->Par1 >= 0 && event->Par1 <= PIN_D_MAX)
{
pinMode(event->Par1, OUTPUT);
digitalWrite(event->Par1, event->Par2);
@@ -260,19 +256,16 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
}
}
if ((command == F("longpulse")) || (command == F("longpulse_ms")))
if (command == F("longpulse"))
{
boolean time_in_msec = command == F("longpulse_ms");
success = true;
if (event->Par1 >= 0 && event->Par1 <= 16)
if (event->Par1 >= 0 && event->Par1 <= PIN_D_MAX)
{
pinMode(event->Par1, OUTPUT);
digitalWrite(event->Par1, event->Par2);
setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_OUTPUT, event->Par2);
setSystemTimer(time_in_msec ? event->Par3 : event->Par3 * 1000,
PLUGIN_ID_001, event->Par1, !event->Par2, 0);
log = String(F("SW : GPIO ")) + String(event->Par1) +
String(F(" Pulse set for ")) + String(event->Par3) + String(time_in_msec ? F(" msec") : F(" sec"));
setSystemTimer(event->Par3 * 1000, PLUGIN_ID_001, event->Par1, !event->Par2, 0);
log = String(F("SW : GPIO ")) + String(event->Par1) + String(F(" Pulse set for ")) + String(event->Par3) + String(F(" S"));
addLog(LOG_LEVEL_INFO, log);
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_001, event->Par1, log, 0));
}
@@ -287,12 +280,16 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
case 1:
//IRAM: doing servo stuff uses 740 bytes IRAM. (doesnt matter how many instances)
servo1.attach(event->Par2);
servo1.write(event->Par3);
#if defined(ESP8266)
servo1.attach(event->Par2);
servo1.write(event->Par3);
#endif
break;
case 2:
servo2.attach(event->Par2);
servo2.write(event->Par3);
#if defined(ESP8266)
servo2.attach(event->Par2);
servo2.write(event->Par3);
#endif
break;
}
setPinState(PLUGIN_ID_001, event->Par2, PIN_MODE_SERVO, event->Par3);
@@ -317,6 +314,7 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
outputstate[event->Par1] = event->Par2;
}
// FIXME: Absolutely no error checking in play_rtttl, until then keep it only in testing
#ifdef PLUGIN_BUILD_TESTING
//play a tune via a RTTTL string, look at https://www.letscontrolit.com/forum/viewtopic.php?f=4&t=343&hilit=speaker&start=10 for more info.
if (command == F("rtttl"))
@@ -325,10 +323,11 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
if (event->Par1 >= 0 && event->Par1 <= 16)
{
pinMode(event->Par1, OUTPUT);
char sng[1024] ="";
string.replace("-","#");
string.toCharArray(sng, 1024);
play_rtttl(event->Par1, sng);
// char sng[1024] ="";
String tmpString=string;
tmpString.replace("-","#");
// tmpString.toCharArray(sng, 1024);
play_rtttl(event->Par1, tmpString.c_str());
setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_OUTPUT, event->Par2);
log = String(F("SW : ")) + string;
addLog(LOG_LEVEL_INFO, log);
@@ -340,7 +339,7 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
if (command == F("tone"))
{
success = true;
if (event->Par1 >= 0 && event->Par1 <= 16)
if (event->Par1 >= 0 && event->Par1 <= PIN_D_MAX)
{
pinMode(event->Par1, OUTPUT);
tone(event->Par1, event->Par2, event->Par3);
@@ -365,19 +364,28 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
return success;
}
// TD-er: Needed to fix a mistake in earlier fixes.
byte P001_getSwitchType(struct EventStruct *event) {
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
switch (choice) {
case 2: // Old implementation for Dimmer
case PLUGIN_001_TYPE_DIMMER:
choice = PLUGIN_001_TYPE_DIMMER;
break;
case 1: // Old implementation for switch
case PLUGIN_001_TYPE_SWITCH:
default:
choice = PLUGIN_001_TYPE_SWITCH;
break;
}
return choice;
#if defined(ESP32)
void analogWriteESP32(int pin, int value)
{
// find existing channel if this pin has been used before
int8_t ledChannel = -1;
for(byte x = 0; x < 16; x++)
if (ledChannelPin[x] == pin)
ledChannel = x;
if(ledChannel == -1) // no channel set for this pin
{
for(byte x = 0; x < 16; x++) // find free channel
if (ledChannelPin[x] == -1)
{
int freq = 5000;
ledChannelPin[x] = pin; // store pin nr
ledcSetup(x, freq, 10); // setup channel
ledcAttachPin(pin, x); // attach to this pin
ledChannel = x;
break;
}
}
ledcWrite(ledChannel, value);
}
#endif
+17 -2
View File
@@ -47,6 +47,11 @@ boolean Plugin_002(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
#if defined(ESP32)
string += F("<TR><TD>Analog Pin:<TD>");
addPinSelect(false, string, "taskdevicepin1", Settings.TaskDevicePin1[event->TaskIndex]);
#endif
addFormCheckBox(string, F("Oversampling"), F("plugin_002_oversampling"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
addFormSubHeader(string, F("Two Point Calibration"));
@@ -85,7 +90,12 @@ boolean Plugin_002(byte function, struct EventStruct *event, String& string)
{
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0]) //Oversampling?
{
Plugin_002_OversamplingValue += analogRead(A0);
#if defined(ESP8266)
Plugin_002_OversamplingValue += analogRead(A0);
#endif
#if defined(ESP32)
Plugin_002_OversamplingValue += analogRead(Settings.TaskDevicePin1[event->TaskIndex]);
#endif
Plugin_002_OversamplingCount ++;
}
success = true;
@@ -106,7 +116,12 @@ boolean Plugin_002(byte function, struct EventStruct *event, String& string)
}
else
{
int16_t value = analogRead(A0);
#if defined(ESP8266)
int16_t value = analogRead(A0);
#endif
#if defined(ESP32)
int16_t value = analogRead(Settings.TaskDevicePin1[event->TaskIndex]);
#endif
UserVar[event->BaseVarIndex] = (float)value;
log += value;
+57 -55
View File
@@ -2,6 +2,8 @@
// #################################### Plugin 004: TempSensor Dallas DS18B20 ###########################
// #######################################################################################################
// Maxim Integrated (ex Dallas) DS18B20 datasheet : https://datasheets.maximintegrated.com/en/ds/DS18B20.pdf
#define PLUGIN_004
#define PLUGIN_ID_004 4
#define PLUGIN_NAME_004 "Environment - DS18b20"
@@ -52,9 +54,8 @@ boolean Plugin_004(byte function, struct EventStruct * event, String& string)
Plugin_004_DallasPin = Settings.TaskDevicePin1[event->TaskIndex];
// get currently saved address
for (byte i = 0; i < 8; i++) {
for (byte i = 0; i < 8; i++)
savedAddress[i] = ExtraTaskSettings.TaskDevicePluginConfigLong[i];
}
// find all suitable devices
addRowLabel(string, F("Device Address"));
@@ -104,6 +105,7 @@ boolean Plugin_004(byte function, struct EventStruct * event, String& string)
ExtraTaskSettings.TaskDevicePluginConfigLong[x] = addr[x];
Plugin_004_DS_setResolution(addr, getFormItemInt(F("plugin_004_res")));
Plugin_004_DS_startConvertion(addr);
success = true;
break;
@@ -133,6 +135,7 @@ boolean Plugin_004(byte function, struct EventStruct * event, String& string)
Plugin_004_DallasPin = Settings.TaskDevicePin1[event->TaskIndex];
float value = 0;
String log = F("DS : Temperature: ");
if (Plugin_004_DS_readTemp(addr, &value))
{
UserVar[event->BaseVarIndex] = value;
@@ -144,6 +147,7 @@ boolean Plugin_004(byte function, struct EventStruct * event, String& string)
UserVar[event->BaseVarIndex] = NAN;
log += F("Error!");
}
Plugin_004_DS_startConvertion(addr);
log += (" (");
for (byte x = 0; x < 8; x++)
@@ -167,23 +171,39 @@ boolean Plugin_004(byte function, struct EventStruct * event, String& string)
\*********************************************************************************************/
byte Plugin_004_DS_scan(byte getDeviceROM, uint8_t* ROM)
{
byte tmpaddr[8];
byte devCount = 0;
Plugin_004_DS_reset();
byte tmpaddr[8];
byte devCount = 0;
Plugin_004_DS_reset();
Plugin_004_DS_reset_search();
while (Plugin_004_DS_search(tmpaddr))
{
if (getDeviceROM == devCount)
for (byte i = 0; i < 8; i++)
ROM[i] = tmpaddr[i];
devCount++;
}
return devCount;
Plugin_004_DS_reset_search();
while (Plugin_004_DS_search(tmpaddr))
{
if (getDeviceROM == devCount)
for (byte i = 0; i < 8; i++)
ROM[i] = tmpaddr[i];
devCount++;
}
return devCount;
}
/*********************************************************************************************\
* Dallas Read temperature
* Dallas Start Temperature Conversion, expected duration:
* 9 bits resolution -> 93.75 ms
* 10 bits resolution -> 187.5 ms
* 11 bits resolution -> 375 ms
* 12 bits resolution -> 750 ms
\*********************************************************************************************/
void Plugin_004_DS_startConvertion(uint8_t ROM[8])
{
Plugin_004_DS_reset();
Plugin_004_DS_write(0x55); // Choose ROM
for (byte i = 0; i < 8; i++)
Plugin_004_DS_write(ROM[i]);
Plugin_004_DS_write(0x44); // Take temperature mesurement
}
/*********************************************************************************************\
* Dallas Read temperature from scratchpad
\*********************************************************************************************/
boolean Plugin_004_DS_readTemp(uint8_t ROM[8], float * value)
{
@@ -194,20 +214,13 @@ boolean Plugin_004_DS_readTemp(uint8_t ROM[8], float * value)
Plugin_004_DS_write(0x55); // Choose ROM
for (byte i = 0; i < 8; i++)
Plugin_004_DS_write(ROM[i]);
Plugin_004_DS_write(0x44);
delay(800);
Plugin_004_DS_reset();
Plugin_004_DS_write(0x55); // Choose ROM
for (byte i = 0; i < 8; i++)
Plugin_004_DS_write(ROM[i]);
Plugin_004_DS_write(0xBE); // Read scratchpad
for (byte i = 0; i < 9; i++) // copy 8 bytes
for (byte i = 0; i < 9; i++) // read 9 bytes
ScratchPad[i] = Plugin_004_DS_read();
if (Plugin_004_DS_crc8(ScratchPad, 8) != ScratchPad[8])
if (!Plugin_004_DS_crc8(ScratchPad))
{
*value = 0;
return false;
@@ -222,15 +235,11 @@ boolean Plugin_004_DS_readTemp(uint8_t ROM[8], float * value)
{
DSTemp = (ScratchPad[1] << 11) | ScratchPad[0] << 3;
DSTemp = ((DSTemp & 0xfff0) << 3) - 16 +
(
((ScratchPad[7] - ScratchPad[6]) << 7) /
ScratchPad[7]
);
(((ScratchPad[7] - ScratchPad[6]) << 7) / ScratchPad[7]);
*value = float(DSTemp) * 0.0078125;
}
return true;
} // Plugin_004_DS_readTemp
}
/*********************************************************************************************\
* Dallas Get Resolution
@@ -245,19 +254,15 @@ int Plugin_004_DS_getResolution(uint8_t ROM[8])
Plugin_004_DS_reset();
Plugin_004_DS_write(0x55); // Choose ROM
for (byte i = 0; i < 8; i++)
{
Plugin_004_DS_write(ROM[i]);
}
Plugin_004_DS_write(0xBE); // Read scratchpad
for (byte i = 0; i < 9; i++) // copy 8 bytes
for (byte i = 0; i < 9; i++) // read 9 bytes
ScratchPad[i] = Plugin_004_DS_read();
if (Plugin_004_DS_crc8(ScratchPad, 8) != ScratchPad[8])
{
if (!Plugin_004_DS_crc8(ScratchPad))
return 0;
}
else
{
switch (ScratchPad[4])
@@ -272,6 +277,7 @@ int Plugin_004_DS_getResolution(uint8_t ROM[8])
return 10;
case 0x1F: // 9 bit
default:
return 9;
}
}
@@ -291,44 +297,38 @@ boolean Plugin_004_DS_setResolution(uint8_t ROM[8], byte res)
Plugin_004_DS_reset();
Plugin_004_DS_write(0x55); // Choose ROM
for (byte i = 0; i < 8; i++)
{
Plugin_004_DS_write(ROM[i]);
}
Plugin_004_DS_write(0xBE); // Read scratchpad
for (byte i = 0; i < 9; i++) // copy 8 bytes
for (byte i = 0; i < 9; i++) // read 9 bytes
ScratchPad[i] = Plugin_004_DS_read();
if (Plugin_004_DS_crc8(ScratchPad, 8) != ScratchPad[8])
{
return 0;
}
if (!Plugin_004_DS_crc8(ScratchPad))
return false;
else
{
switch (res)
{
case 12:
ScratchPad[4] = 0x7F; // 12 bit
ScratchPad[4] = 0x7F; // 12 bits
break;
case 11:
ScratchPad[4] = 0x5F; // 11 bit
ScratchPad[4] = 0x5F; // 11 bits
break;
case 10:
ScratchPad[4] = 0x3F; // 10 bit
ScratchPad[4] = 0x3F; // 10 bits
break;
case 9:
default:
ScratchPad[4] = 0x1F; // 9 bit
ScratchPad[4] = 0x1F; // 9 bits
break;
}
Plugin_004_DS_reset();
Plugin_004_DS_write(0x55); // Choose ROM
for (byte i = 0; i < 8; i++)
{
Plugin_004_DS_write(ROM[i]);
}
Plugin_004_DS_write(0x4E); // Write to EEPROM
Plugin_004_DS_write(ScratchPad[2]); // high alarm temp
@@ -337,9 +337,7 @@ boolean Plugin_004_DS_setResolution(uint8_t ROM[8], byte res)
Plugin_004_DS_write(0x55); // Choose ROM
for (byte i = 0; i < 8; i++)
{
Plugin_004_DS_write(ROM[i]);
}
// save the newly written values to eeprom
Plugin_004_DS_write(0x48);
@@ -594,13 +592,17 @@ void Plugin_004_DS_write_bit(uint8_t v)
}
}
uint8_t Plugin_004_DS_crc8(uint8_t * addr, uint8_t len)
/*********************************************************************************************\
* Dallas Calculate CRC8 and compare it of addr[0-7] and compares it to addr[8]
\*********************************************************************************************/
boolean Plugin_004_DS_crc8(uint8_t * addr)
{
uint8_t crc = 0;
uint8_t crc = 0;
uint8_t len = 8;
while (len--)
{
uint8_t inbyte = *addr++;
uint8_t inbyte = *addr++; // from 0 to 7
for (uint8_t i = 8; i; i--)
{
uint8_t mix = (crc ^ inbyte) & 0x01;
@@ -609,5 +611,5 @@ uint8_t Plugin_004_DS_crc8(uint8_t * addr, uint8_t len)
inbyte >>= 1;
}
}
return crc;
return crc == *addr; // addr 8
}

Some files were not shown because too many files have changed in this diff Show More