Compare commits

...

156 Commits

Author SHA1 Message Date
mathieu ec2e28a5b6 Merge pull request 'scd4x' (#1) from scd4x into master
Reviewed-on: #1
2023-11-28 23:12:28 +01:00
Mathieu Maret 06f94a2ee7 SCD4X is disabled by default 2023-11-28 23:10:50 +01:00
Mathieu Maret ccfc148e31 SCD4X: add information on html page 2023-11-28 22:57:29 +01:00
Mathieu Maret 346d7927d8 SCD4X: Setup and MQTT 2023-11-27 23:47:53 +01:00
Mathieu Maret 0f8c14e51e Add basic sensor files for SCD4x 2023-11-27 23:32:45 +01:00
Mathieu Maret a6281c5581 BME680: remove uneeded includes 2023-11-27 23:32:13 +01:00
Mathieu Maret efc7331f25 Default cfg for BMP280 2023-04-17 22:01:21 +02:00
Mathieu Maret 5bef410167 Add BMP280 support 2023-04-14 09:23:32 +02:00
Mathieu Maret f9985cc2c1 Fix wifi reconnect on wifi on/off 2023-03-28 14:27:45 +02:00
Mathieu Maret ef446ebd19 Teleinfo: pull data at every loop
to avoid overflow in libteleinfo
2023-03-28 14:05:14 +02:00
Mathieu Maret 5987bc28de Teleinfo: fix signature 2023-03-28 14:01:46 +02:00
Mathieu Maret 0847e89960 Display more teleinfo information 2022-09-25 00:09:04 +02:00
Mathieu Maret 7cac6f89f1 make sampling periode configurable 2022-09-10 23:18:52 +02:00
Mathieu Maret 7b1d9ae63e Avoid some mqtt server connection
Do not check subscription when we do not subscribe
2022-09-10 22:48:37 +02:00
Mathieu Maret 73d6e17dc1 Merge branch 'teleinfo' 2022-09-10 21:53:45 +02:00
Mathieu Maret 1b52a80b15 Fix teleinfo configuration 2022-09-10 21:53:06 +02:00
Mathieu Maret cbce043f30 BME680 fix hPA unit 2022-09-07 22:58:44 +02:00
Mathieu Maret e68eec8955 Increase Wifi connection time before reconfig 2022-09-07 22:58:23 +02:00
Mathieu Maret 8f471fc0bf WIP: working teleinfo 2021-02-18 23:50:54 +01:00
Mathieu Maret 8fed8bedf4 Add missing files 2021-02-18 15:51:49 +01:00
Mathieu Maret 9110ae3589 Add teleinfo module 2021-02-18 00:25:45 +01:00
Mathieu Maret e60b8ef8ae Fix some possible redefinition 2021-02-16 21:19:20 +01:00
Mathieu Maret 1cd02f0fbc Merge branch 'bme680_bsec' into 'master'
Bme680 bsec

See merge request Mathieu/Domotique!2
2020-07-28 19:54:04 +02:00
Mathieu Maret 0e3afa391b Add check on EEPROM size 2020-07-28 19:51:57 +02:00
Mathieu Maret 976a9a8053 Add bme680 bsec 2020-07-28 19:51:57 +02:00
Mathieu Maret fc6020e703 Add instruction to install Bosch Sensortec Environmental Cluster library 2020-07-28 16:57:03 +02:00
Mathieu Maret cd117f342c more const 2020-03-09 22:38:43 +01:00
Mathieu Maret 5f5bd1b8ae display bme information on webpage + refacto 2020-02-28 23:40:35 +01:00
Mathieu Maret c476f38428 improve default configuration 2020-02-28 17:16:56 +01:00
Mathieu Maret 0c9e8b977b Bme fixes 2020-02-28 17:16:39 +01:00
Mathieu Maret 1b33362577 Update deps description 2020-02-28 17:03:49 +01:00
Mathieu Maret 9f14016abf Add bme680 sensor 2020-02-27 00:07:30 +01:00
Mathieu Maret 817f777418 Fix Wifi connecting 2019-06-04 23:52:25 +02:00
Mathieu Maret 9ac0f2edb8 Fix MqttBatchPublish 2019-06-04 23:18:17 +02:00
Mathieu Maret fea3b73f54 WebServer: improve Setup
Keep password.
Fix ip mode previous state
2019-06-03 00:07:12 +02:00
Mathieu Maret ac6ab8969c Fix static IP EEPROM save 2019-06-03 00:05:21 +02:00
Mathieu Maret 850391ccce Readmes update branch to use 2019-05-14 23:45:20 +02:00
Mathieu Maret caf88dcd98 Mqtt: use batch publish to generalize code
And fix indentation
2019-05-14 23:44:46 +02:00
Mathieu Maret eab447abc6 Merge branch 'bssid_channel' into 'master'
Can store BSSID and CHANNEL

See merge request Mathieu/Domotique!1
2019-04-28 14:49:17 +02:00
Mathieu Maret fc3fa2fc45 Can store BSSID and CHANNEL
This allow faster network connection.
Could be usefull for battery powered application
2018-12-19 22:36:19 +01:00
Mathieu 4121965de7 Add build status in desciption 2017-04-18 15:22:46 +02:00
Mathieu Maret a1e40b150f Remove the /otamode link in index 2017-04-08 14:10:39 +02:00
Mathieu 7839671bf8 Merge branch 'web_ota' into 'master'
Add the possibility to upload OTA by http

Closes #2

See merge request !8
2017-03-29 23:25:17 +02:00
Mathieu Maret 66e153e527 Add link to home page for http OTA
Remove link for regular ota mode
Fix #2
2017-03-29 23:19:42 +02:00
Mathieu Maret fa042404b2 Add the possibility to upload OTA by http 2017-03-29 21:55:14 +02:00
Mathieu abbfec48c9 Update Readme.md to use mqtt fork 2017-03-08 15:28:46 +01:00
Mathieu f31c5f3854 Merge branch 'mqtt_retain' into 'master'
Mqtt retain

See merge request !7
2017-03-08 15:26:33 +01:00
Mathieu b370a109f6 Use Adafruit_MQTT fork that support retains 2017-03-08 15:12:56 +01:00
Mathieu Maret 1166ef1a79 MQTT publisher can set retain flag
Add this flag for IP adress publisher
2017-03-06 23:30:21 +01:00
Mathieu b574bfbc55 Delete TODO.md.
Move information into gitlab board
2017-01-31 17:50:37 +01:00
Mathieu Maret d954883d19 Add bureau conf 2017-01-28 14:32:17 +01:00
Mathieu Maret d5a8232e43 Fix reconfiguration when wifi unreachable 2017-01-28 14:30:25 +01:00
Mathieu e9a7cb8745 Run cppcheck with CI 2017-01-20 01:21:57 +01:00
Mathieu Maret f99fcba6d5 Update TODO
GPIO with interupt done
MQTT optionnal
WEB itf optionnal
2017-01-06 21:58:33 +01:00
Mathieu Maret 678eafe1a5 Correct few warning 2017-01-01 23:35:19 +01:00
Mathieu Maret f4541a6fd6 OTA does not need a reboot anymore 2016-12-14 22:57:01 +01:00
Mathieu Maret 0396ccfb45 Web itf show GpioObserved status 2016-12-14 22:19:17 +01:00
Mathieu Maret 3957d9645f mqtt deal with IRQ for GPIO 2016-12-14 00:08:47 +01:00
Mathieu Maret 80252f9307 Refactor GPIO listened/controlled configuration
And improve mqtt connection checking
2016-12-13 23:43:37 +01:00
Mathieu Maret d20d756677 Do not display wifi psswd in serial 2016-12-09 22:56:26 +01:00
Mathieu Maret 13c2d23330 All controlled gpio have a single config entry
They get be set/get by mqtt and set by http
2016-12-09 22:55:12 +01:00
Mathieu 1a2d3a3eb6 Merge branch 'MQTT_refacto' into 'master'
Mqtt refacto

MQTT and EEPROM code simplification.
Save about 1k

See merge request !6
2016-11-20 00:30:42 +01:00
Mathieu Maret 207c104c07 Few little fix 2016-11-20 00:23:16 +01:00
Mathieu Maret 3691745aec Put config into a struct 2016-11-20 00:06:31 +01:00
Mathieu Maret 6f6c0f7525 Use template for MqttPublish functions
And rename Mqtt*Publish function into MqttPublish*
2016-11-16 16:59:17 +01:00
Mathieu Maret 3d82e2a200 Use Reprog button as setup button on long press 2016-11-16 00:00:47 +01:00
Mathieu Maret d49e0a5fff Use MQTT only in normal mode 2016-11-15 23:53:48 +01:00
Mathieu Maret d6a2be13e1 Default value for CONFIG_DISABLE{WEB,OTA,MQTT} 2016-10-28 18:06:57 +02:00
Mathieu Maret e0f600baf0 Possibility to disable MQTT
save ~6k
2016-10-28 18:04:30 +02:00
Mathieu Maret 87085fba3d Possibility to disable OTA
save ~3k
2016-10-28 18:03:36 +02:00
Mathieu Maret a14210e0d9 Possibility to disable Web interface
Save ~12k
2016-10-28 18:02:39 +02:00
Mathieu Maret 76c06690a2 Fix MQTT publishing when mqtt is not configured 2016-10-28 00:21:12 +02:00
Mathieu Maret 0a55298feb Add option to disable SSL
it disable mqtts but save ~50ko
2016-09-28 23:19:12 +02:00
Mathieu 3527184ce0 Merge branch 'pwm' into 'master'
Pwm



See merge request !5
2016-09-28 23:14:43 +02:00
Mathieu Maret 997f63b917 Add PWM controlled by web 2016-09-28 23:11:08 +02:00
Mathieu Maret 0ccf653cc6 Build HTML to control GPIO one time only 2016-09-28 15:28:02 +02:00
Mathieu Maret c911376cce PWM controlled by mqtt 2016-09-28 14:08:43 +02:00
Mathieu Maret 34b624b9a0 Code cleaning 2016-09-28 13:45:01 +02:00
Mathieu Maret 640db6c27d Small Warning fix & print simplification 2016-09-28 00:34:23 +02:00
Mathieu Maret 3a6987af44 Fix strange indent in MQTT 2016-09-28 00:34:23 +02:00
Mathieu Maret 20e4869a21 Simplify MQTT code 2016-09-28 00:34:23 +02:00
Mathieu ad7b6b3213 Updater: Show dialog on sucsess 2016-09-22 13:20:19 +02:00
Mathieu Maret 4d918e4e15 Updater: job in a thread
Add a progress bar
Put device in OTA mode automatically
2016-09-22 12:58:55 +02:00
Mathieu Maret a66a8fe6ec Updater: add info on espota.py 2016-09-21 23:52:52 +02:00
Mathieu Maret 238b26067e Updater: refact as a class 2016-09-21 23:48:18 +02:00
Mathieu Maret ed0364eb7a Updater: Cleaning 2016-09-21 23:31:14 +02:00
Mathieu b43feb922d Add a ugly gui for espota 2016-09-21 18:44:41 +02:00
Mathieu Maret 738ccfd14a Add Wifi Strength to HTML Info 2016-09-21 16:02:52 +02:00
Mathieu b5b4220c4b Merge branch 'ci' into 'master'
Ci



See merge request !4
2016-09-20 19:18:10 +02:00
Mathieu Maret 286919e45f Add dependencies 2016-09-20 19:14:07 +02:00
Mathieu Maret eeaab5f29e Correct sketch path 2016-09-20 18:47:00 +02:00
Mathieu 83afc2e845 Merge branch 'WebGpioArray' into 'master'
Use Array to define GPIO controlled by Web



See merge request !3
2016-09-20 18:30:00 +02:00
Mathieu Maret 1a7b3ec53a Use Array to define GPIO controlled by Web 2016-09-20 18:28:32 +02:00
Mathieu 2e94b98ef2 Merge branch 'mqtts' into 'master'
Enable MQTTS using port 8883



See merge request !2
2016-09-20 12:09:37 +02:00
Mathieu 979bb58a4b Update Readme.md 2016-09-15 22:58:05 +02:00
Mathieu Maret 12c5b9e1b7 Enable MQTTS using port 8883 2016-09-15 22:43:00 +02:00
Mathieu Maret d0707599c2 Use local x11 2016-08-05 14:27:45 +02:00
Mathieu Maret 487a7c6d77 All build in 1 step 2016-07-10 13:59:36 +02:00
Mathieu Maret e4b0914238 Install arduino env for CI 2016-07-10 01:35:56 +02:00
Mathieu Maret 8a92263ae0 Correct WiFiAccessPointConfigurator ino for CI 2016-07-10 01:18:58 +02:00
Mathieu Maret 599b7f5033 add WiFiAccessPointConfigurator to Ci 2016-07-10 01:01:18 +02:00
Mathieu Maret 5315e7dffa Add WiFiWebServer to CI 2016-07-09 23:36:29 +02:00
Mathieu Maret 778b60af95 Add .gitlab-ci.yml 2016-07-09 23:16:50 +02:00
Mathieu Maret d3d7e0318a you can configure DHT type 2016-07-09 14:35:55 +02:00
Mathieu Maret a68a207fa1 Suggest SSID name when configuring Wifi Details 2016-07-08 16:04:20 +02:00
Mathieu Maret 810c9b881c Add a way to test Wifi Config in AP mode 2016-07-08 01:03:32 +02:00
Mathieu Maret 2515e577a6 Fix indent in DHT 2016-07-08 01:02:01 +02:00
Mathieu Maret 406eaaa24e Add Esp8266-Arduino-Makefile as a submodule 2016-06-22 00:44:25 +02:00
Mathieu Maret 967c6c736f Feed Ipaddress by MQTT 2016-06-18 02:24:00 +02:00
Mathieu Maret 286844dd6d GPIO used to enter setup in now configurable 2016-06-18 01:49:29 +02:00
Mathieu Maret ae77a7a8ee Correct bmp180 setup return value when disabled 2016-06-18 01:47:35 +02:00
Mathieu Maret 0c3ced5a7f Correct DHT Setup when disabled 2016-06-18 01:34:42 +02:00
Mathieu Maret bd7979a1f3 Enable light sleep by default 2016-06-09 21:37:59 +02:00
Mathieu Maret d35652dbf7 Correct DrySetup when disabled 2016-06-09 21:37:44 +02:00
Mathieu Maret 5db953072d Return dryness to http and mqtt 2016-06-04 18:45:11 +02:00
Mathieu Maret 4c09dcbb24 Add the dry sensor 2016-06-02 01:31:57 +02:00
Mathieu Maret 786fedc74f Same return value for every sensor after Setup() 2016-06-02 01:28:16 +02:00
Mathieu Maret ff4f72e1f7 Revert "Compact some code"
Arduino Serial does not really support printf
This reverts commit 85f0bf5c78.
2016-06-02 00:40:43 +02:00
Mathieu Maret 075ed120aa EEPROM have its own header 2016-06-01 15:21:32 +02:00
Mathieu Maret 7e25978455 Disable switch off of internal LED when saving power
It may disable GPIO used by sensors
2016-06-01 01:49:04 +02:00
Mathieu Maret 69fd24b756 Start loop with a measure 2016-06-01 01:23:23 +02:00
Mathieu Maret 04690a4c66 MDNS is optionnal 2016-06-01 01:22:47 +02:00
Mathieu Maret e97777eed3 Config option to disable MDNS 2016-06-01 01:16:01 +02:00
Mathieu Maret 4d38c2c7a5 MQTT: add user name in URL
So we can support several user on the same server.
URL are /feeds/USER/DEVICE/....
2016-06-01 00:49:42 +02:00
Mathieu Maret 85f0bf5c78 Compact some code 2016-06-01 00:44:14 +02:00
Mathieu Maret 26d3deee0e Code simplification 2016-06-01 00:36:14 +02:00
Mathieu Maret 31e9c04e82 Even initialize int 2016-04-14 01:38:06 +02:00
Mathieu Maret 5c8ab4ce97 Fix needed CONFIG_ when surrounding CONFIG is not defined 2016-04-14 01:38:06 +02:00
Mathieu Maret 3eb9298cb1 Correct mqtt simplification 2016-04-14 01:38:06 +02:00
Mathieu Maret 8101e7bd36 Simplify MQTT sensor setup 2016-04-14 01:15:42 +02:00
Mathieu Maret 6ce9e63a22 TODO: static ip conf done 2016-04-14 00:39:25 +02:00
Mathieu Maret 10e0425acd Simplify force setup code
And make sure that previous AP is not enabled
2016-04-10 02:01:25 +02:00
Mathieu Maret 4cb6516b75 Mqtt: avoid crash when not configured 2016-04-10 01:59:37 +02:00
Mathieu Maret beae8b335b Include build date into web interface 2016-04-10 00:37:41 +02:00
Mathieu Maret ae6e03d67e Change default config behavior
Do not force values but print error message a compile time
2016-04-10 00:10:02 +02:00
Mathieu Maret 1bbd52a234 Add MQTT generic publisher function 2016-04-08 01:03:57 +02:00
Mathieu Maret 85196a7563 Fix Warnings 2016-04-07 23:52:37 +02:00
Mathieu Maret 08a02651a6 Fix Web Gpio control configuration 2016-04-07 15:46:32 +02:00
Mathieu Maret 4536163cfd Web Interface print DHT info 2016-04-07 15:45:55 +02:00
Mathieu Maret bdbcfd25d4 DHT: get temp and humidity
And save them with mqtt
2016-04-07 15:26:01 +02:00
Mathieu Maret 0a2f18b8ee Add info for BMP fork in code 2016-04-07 13:37:55 +02:00
Mathieu Maret 9646eab78f Use MQTT in NORMAL mode only
and fix EEPROM size configuration
2016-04-07 12:24:30 +02:00
Mathieu Maret e1673f6c22 Display configured IP value in setup page 2016-04-07 12:05:37 +02:00
Mathieu Maret 50bf6c7d57 dht: add mqtt entries 2016-04-07 02:04:38 +02:00
Mathieu Maret c497069bf5 add more in todo 2016-04-07 02:03:50 +02:00
Mathieu Maret e82378e224 Save Static ip config as uint32_t 2016-04-07 02:02:51 +02:00
Mathieu Maret 96149ab5da Fix config inheritage 2016-04-07 01:59:20 +02:00
Mathieu Maret 132ba26720 Save ip config into eeprom 2016-04-06 19:34:29 +02:00
Mathieu Maret fe3dba6cad Add CONFIG_ENABLE_POWER_SAVE
Enable light sleep
Switch off internal LED
Disable mDNS
2016-04-06 16:03:14 +02:00
Mathieu Maret 0190133bf3 Disable more code when bmp is not enabled 2016-04-06 15:51:27 +02:00
Mathieu Maret 2778443ccc Implement light sleep 2016-04-01 01:06:13 +02:00
Mathieu Maret a204d6fddf Reindent 2016-04-01 01:05:29 +02:00
Mathieu Maret 0dd9901d19 Avoid mqtt communication if mqtt is not configured 2016-04-01 01:05:03 +02:00
Mathieu Maret b843eeb184 Add Todo 2016-03-30 00:57:16 +02:00
Mathieu Maret cdfafd2d45 Config EEPROM size like other configs 2016-03-30 00:49:57 +02:00
Mathieu Maret efe135a801 Move configuration into a dedicated file 2016-03-30 00:44:37 +02:00
31 changed files with 1791 additions and 258 deletions

25
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,25 @@
before_script:
- export DISPLAY=:0.0
- arduino --pref "boardsmanager.additional.urls=http://arduino.esp8266.com/stable/package_esp8266com_index.json" --save-prefs
- arduino --install-boards esp8266:esp8266 || true
#replaced by a fork https://github.com/shmuelzon/Adafruit_MQTT_Library.git that have mqtt retains
# - arduino --install-library "Adafruit MQTT Library" || true
- arduino --install-library "Adafruit BME680 Library" || true
- arduino --install-library "Adafruit Unified Sensor" || true
- arduino --install-library "DHT sensor library" || true
- arduino --install-library "BSEC Software Library" || true
- arduino --board esp8266:esp8266:generic --save-prefs
- arduino --pref "compiler.warning_level=all" --save-prefs
after_script:
WifiControlSensor:
stage: build
script:
- arduino --verify WifiControlSensor/WifiControlSensor.ino
- arduino --verify WiFiWebServer/WiFiWebServer.ino
- arduino --verify WiFiAccessPointConfigurator/WiFiAccessPointConfigurator.ino
cppcheck:
script:
- cppcheck --enable=all --std=c++11 WifiControlSensor/*.{ino,h}

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "Esp8266-Arduino-Makefile"]
path = Esp8266-Arduino-Makefile
url = https://github.com/thunderace/Esp8266-Arduino-Makefile.git

@ -0,0 +1 @@
Subproject commit 6ffd79de30164e67f6c059b7a1792bdc3860e973

View File

@ -1,3 +1,5 @@
[![build status](https://gitlab.mathux.org/Mathieu/Domotique/badges/master/build.svg)](https://gitlab.mathux.org/Mathieu/Domotique/commits/master)
# Introduction # Introduction
This is a bunch of project that aims to provide a reusable platform for different kind of project using ESP8266. This is a bunch of project that aims to provide a reusable platform for different kind of project using ESP8266.
@ -20,10 +22,26 @@ Settings can be reconfigured latter by web interface or by pulling down gpio 3
Device can also be put in OTA mode and will wait for OTA from the espota tool. Device can also be put in OTA mode and will wait for OTA from the espota tool.
## WifiControlSensor ## WifiControlSensor
Provide previous WiFiAccessPointConfigurator features and can also measure temperature and pressure from a BMP180. Provide previous WiFiAccessPointConfigurator features and can also get measure from several sensors:
Those measure can be shared by MQTT. MQTT details (server, username, passwd, port) can be configured by a web page. * BMP180
* DHT11/22
* Any Analog sensor
Those measure can be shared by MQTT(s). MQTT details (server, username, passwd, port) can be configured by a web page.
To interface with BMP180, the following library should be installed into Arduino environment: https://github.com/mmaret/BMP180_Breakout_Arduino_Library/archive/master.zip To interface with BMP180, the following library should be installed into Arduino environment: https://github.com/mmaret/BMP180_Breakout_Arduino_Library/archive/master.zip
To use mqtt, the Adafruit Mqtt library should be installed. To use mqtt, a fork of the Adafruit Mqtt library should be installed (gitlab@gitlab.mathux.org:Mathieu/adaAdafruit_MQTT_Libraryfruit_mqtt_library.git
-b retain_support).
This have been tested against a mosquitto server This have been tested against a mosquitto server
Quick cmdline to install deps:
cd ~/Arduino/libraries/
git clone gitlab@gitlab.mathux.org:Mathieu/ESP8266_HIB.git
git clone git@github.com:mmaret/BMP180_Breakout_Arduino_Library.git
git clone gitlab@gitlab.mathux.org:Mathieu/adaAdafruit_MQTT_Libraryfruit_mqtt_library.git -b support_retain
arduino --install-library "Adafruit BME680 Library"
arduino --install-library "Adafruit Unified Sensor"
arduino --install-library "DHT sensor library"
arduino --install-library "BSEC Software Library" # Then you have to follow the instruction in the README.md in the BSEC install folder

86
Updater.py Executable file
View File

@ -0,0 +1,86 @@
#!/usr/bin/env python
# Gui to get parameters for espota.py
# espota.py is available https://raw.githubusercontent.com/esp8266/Arduino/master/tools/espota.py
# and should be in the same directory
from tkinter import *
from tkinter import filedialog
from tkinter.messagebox import *
from tkinter.ttk import *
from threading import Thread
import urllib.request
import time
import subprocess
class Updater(Thread):
def __init__(self, gui, ip, file):
Thread.__init__(self)
self.gui = gui
self.ip = ip
self.file = file
def run(self):
self.gui.installButton['state'] = 'disabled'
self.gui.pb["value"] = 1
try:
print("Put device in OTA mode")
urllib.request.urlopen("http://" + self.ip + "/otamode").read()
self.gui.pb["value"] = 2
print("Uploading new firmware")
self.gui.pb["value"] = 3
subprocess.call(["python", "espota.py", "-i",
self.ip, "-f", self.file])
except Exception as e:
showerror("Error", e)
else:
showinfo("Done", "Update installed")
finally:
self.gui.pb["value"] = 4
self.gui.installButton['state'] = 'normal'
class UpdaterGui(Frame):
file = "firmware.bin"
sleep = 0
installButton = None
def __init__(self, win, **kwargs):
Frame.__init__(self, win, **kwargs)
button_opt = {'fill': constants.BOTH, 'padx': 5, 'pady': 5}
Button(win, text='Select firmware',
command=self.askopenfile).pack(**button_opt)
self.ipEntry = Entry(win)
self.ipEntry.pack()
self.ipEntry.delete(0, END)
self.ipEntry.insert(0, "192.168.0.XX")
self.installButton = Button(win, text='Install', command=self.install)
self.installButton.pack(pady=20)
self.pb = Progressbar(win, orient='horizontal', mode='determinate', maximum=4)
self.pb["value"] = 0
self.pb.pack()
def install(self):
if self.file is None:
showerror("Error", "Select a firmware first")
return
self.pb["value"] = 0
ip = self.ipEntry.get()
print("Installing", self.file, "at ip", ip)
installTh = Updater(self, ip, self.file)
installTh.start()
def askopenfile(self):
self.file = filedialog.askopenfilename(
title='Select Firmware', filetypes=[('binaries', '*.bin')])
root = Tk()
root.title("Firmware Updater")
updater = UpdaterGui(root)
updater.mainloop()

View File

@ -0,0 +1,26 @@
#pragma once
#ifdef CONFIG_ENABLE_BME680
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BME680.h"
#include "debug_sketch.h"
#define BME_SCK 13
#define BME_MISO 12
#define BME_MOSI 11
#define BME_CS 10
//Use Default i2c pin GPIO4(D2): SDA, GPIO5(D1):SCL
#define SEALEVELPRESSURE_HPA (1013.25)
int BME680GetMeasure(float &t, float &p, float &h, float &g, float &a);
int BME680Setup();
bool BME680IsConnected();
#else //CONFIG_ENABLE_BME680
int BME680GetMeasure(float &, float &, float&, float &, float &){return -1;};
int BME680Setup(){SKETCH_DEBUG_PRINTLN("BME680 is disabled at build time"); return -1;};
bool BME680IsConnected(){return false;};
#endif

View File

@ -0,0 +1,40 @@
#ifdef CONFIG_ENABLE_BME680
#include "BME680.h"
Adafruit_BME680 bme; // I2C
//Adafruit_BME680 bme(BME_CS); // hardware SPI
//Adafruit_BME680 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK);
int bme680Connected = 0;
int BME680Setup() {
bme680Connected = bme.begin();
if (!bme680Connected){
SKETCH_DEBUG_PRINTLN("Cannot connect to BME680");
return -1;
}
// Set up oversampling and filter initialization
bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X);
bme.setPressureOversampling(BME680_OS_4X);
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme.setGasHeater(320, 150); // 320*C for 150 ms
return 0;
}
bool BME680IsConnected() {
return bme680Connected != 0;
}
int BME680GetMeasure(float &t, float &p, float &h, float &g, float &a){
if(!bme.performReading()){
SKETCH_DEBUG_PRINTLN("Cannot read BME680 measure");
return -1;
}
t = bme.temperature;
p = bme.pressure / 100.0;
h = bme.humidity;
g = bme.gas_resistance / 1000.0;
a = bme.readAltitude(SEALEVELPRESSURE_HPA);
return 0;
}
#endif

View File

@ -0,0 +1,16 @@
#pragma once
#ifdef CONFIG_BME680_BSEC_ENABLE
int BME680BSECGetMeasure(float &t, float &p, float &h, float &iaq, float &iaqAcc);
int BME680BSECSetup();
bool BME680BSECIsConnected();
#else // CONFIG_ENABLE_BME680_BSEC
#define BSEC_MAX_STATE_BLOB_SIZE 0
int BME680BSECGetMeasure(float &, float &, float &, float &, float &) {
return -1;
};
int BME680BSECSetup() {
SKETCH_DEBUG_PRINTLN("BME680 BSEC is disabled at build time");
return -1;
};
bool BME680BSECIsConnected() { return false; };
#endif

View File

@ -0,0 +1,153 @@
#ifdef CONFIG_BME680_BSEC_ENABLE
#include "BME680_BSEC.h"
#include "bsec.h"
/* Configure the BSEC library with information about the sensor
18v/33v = Voltage at Vdd. 1.8V or 3.3V
3s/300s = BSEC operating mode, BSEC_SAMPLE_RATE_LP or BSEC_SAMPLE_RATE_ULP
4d/28d = Operating age of the sensor in days
generic_18v_3s_4d
generic_18v_3s_28d
generic_18v_300s_4d
generic_18v_300s_28d
generic_33v_3s_4d
generic_33v_3s_28d
generic_33v_300s_4d
generic_33v_300s_28d
*/
const uint8_t bsec_config_iaq[] = {
#if CONFIG_SAMPLING_PERIOD_MS == 3000
#include "config/generic_33v_3s_4d/bsec_iaq.txt"
#elif CONFIG_SAMPLING_PERIOD_MS == 300000
#include "config/generic_33v_300s_4d/bsec_iaq.txt"
#else
#error "Unsupport CONFIG_SAMPLING_PERIOD_MS (3000 and 300000 are supported)"
#endif
};
#define STATE_SAVE_PERIOD \
UINT32_C(360 * 60 * 1000) // 360 minutes - 4 times a day
uint16_t stateUpdateCounter = 0;
Bsec iaqSensor;
uint8_t bsecState[BSEC_MAX_STATE_BLOB_SIZE] = {0};
// Helper function definitions
int checkIaqSensorStatus(void) {
if (iaqSensor.status != BSEC_OK) {
if (iaqSensor.status < BSEC_OK) {
SKETCH_DEBUG_PRINTLN("BSEC error code : " + String(iaqSensor.status));
return -2;
} else {
SKETCH_DEBUG_PRINTLN("BSEC warning code : " + String(iaqSensor.status));
return -1;
}
}
if (iaqSensor.bme680Status != BME680_OK) {
if (iaqSensor.bme680Status < BME680_OK) {
SKETCH_DEBUG_PRINTLN("BME680 error code : " + String(iaqSensor.bme680Status));
return -2;
} else {
SKETCH_DEBUG_PRINTLN("BME680 warning code : " + String(iaqSensor.bme680Status));
return -1;
}
}
iaqSensor.status = BSEC_OK;
return 0;
}
void updateState(void)
{
bool update = false;
/* Set a trigger to save the state. Here, the state is saved every STATE_SAVE_PERIOD with the
* first state being saved once the algorithm achieves full calibration, i.e. iaqAccuracy = 3
*/
if (stateUpdateCounter == 0) {
if (iaqSensor.iaqAccuracy >= 3) {
update = true;
stateUpdateCounter++;
}
} else {
/* Update every STATE_SAVE_PERIOD milliseconds */
if ((stateUpdateCounter * STATE_SAVE_PERIOD) < millis()) {
update = true;
stateUpdateCounter++;
}
}
if (update) {
iaqSensor.getState(bsecState);
checkIaqSensorStatus();
SKETCH_DEBUG_PRINTLN("Writing state to EEPROM");
EepromSaveBME680State(bsecState);
}
}
int BME680BSECGetMeasure(float &t, float &p, float &h, float &iaq, float &iaqAcc)
{
if (iaqSensor.run()) { // If new data is available
t = iaqSensor.temperature;
p = iaqSensor.pressure/100;
h = iaqSensor.humidity;
iaq = iaqSensor.iaq;
iaqAcc = iaqSensor.iaqAccuracy;
updateState();
} else {
return -1;
}
return 0;
}
int BME680BSECSetup()
{
Wire.begin();
iaqSensor.begin(CONFIG_BME680_BSEC_I2C_ADDR, Wire);
SKETCH_DEBUG_PRINTLN("\nBSEC library version " + String(iaqSensor.version.major) + "." +
String(iaqSensor.version.minor) + "." + String(iaqSensor.version.major_bugfix) +
"." + String(iaqSensor.version.minor_bugfix));
if (checkIaqSensorStatus())
return -1;
iaqSensor.setConfig(bsec_config_iaq);
if (checkIaqSensorStatus())
return -1;
if (!EepromLoadBME680State(bsecState))
iaqSensor.setState(bsecState);
if (checkIaqSensorStatus())
return -1;
bsec_virtual_sensor_t sensorList[7] = {
BSEC_OUTPUT_RAW_TEMPERATURE,
BSEC_OUTPUT_RAW_PRESSURE,
BSEC_OUTPUT_RAW_HUMIDITY,
BSEC_OUTPUT_RAW_GAS,
BSEC_OUTPUT_IAQ,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
};
iaqSensor.updateSubscription(sensorList, 7, BSEC_SAMPLE_RATE_LP);
if (checkIaqSensorStatus())
return -1;
return 0;
}
bool BME680BSECIsConnected()
{
if (checkIaqSensorStatus())
return false;
return true;
}
#endif

View File

@ -1,21 +1,18 @@
#pragma once #pragma once
#ifdef ENABLE_BMP180 #ifdef CONFIG_ENABLE_BMP180
#include <SFE_BMP180.h> #include <SFE_BMP180.h>
#include "debug_sketch.h" #include "debug_sketch.h"
// Get Current altitude with http://fr.mygeoposition.com/ // Get Current altitude with http://fr.mygeoposition.com/
#define ALTITUDE 130 #define ALTITUDE 130
SFE_BMP180 bmp180;
int bmp180Connected = 0;
int BMP180GetTemperature(double &t); int BMP180GetTemperature(double &t);
int BMP180GetTempAndPressure(double &t, double &p); int BMP180GetTempAndPressure(double &t, double &p);
int BMP180Setup(int sda, int scl); int BMP180Setup(int sda, int scl);
bool BMP180IsConnected(); bool BMP180IsConnected();
#else //ENABLE_BMP80 #else //CONFIG_ENABLE_BMP80
int BMP180GetTemperature(double &t){return 0;}; int BMP180GetTemperature(double &){return -1;};
int BMP180GetTempAndPressure(double &t, double &p){return 0;}; int BMP180GetTempAndPressure(double &, double &){return -1;};
int BMP180Setup(int , int ){SKETCH_DEBUG_PRINTLN("BMP180 is disabled at build time"); return 0;}; int BMP180Setup(int , int ){SKETCH_DEBUG_PRINTLN("BMP180 is disabled at build time"); return -1;};
bool BMP180IsConnected(){return 0;}; bool BMP180IsConnected(){return false;};
#endif #endif

View File

@ -1,8 +1,16 @@
#ifdef ENABLE_BMP180 #ifdef CONFIG_ENABLE_BMP180
#include "BMP180.h" #include "BMP180.h"
SFE_BMP180 bmp180;
int bmp180Connected = 0;
int BMP180Setup(int sda, int scl) { int BMP180Setup(int sda, int scl) {
//Use BMP fork at https://github.com/mmaret/BMP180_Breakout_Arduino_Library/archive/master.zip
bmp180Connected = bmp180.begin(sda, scl); bmp180Connected = bmp180.begin(sda, scl);
return bmp180Connected; if (!bmp180Connected){
SKETCH_DEBUG_PRINTLN("Cannot connect to BMP180");
return -1;
}
return 0;
} }
bool BMP180IsConnected() { bool BMP180IsConnected() {
@ -11,6 +19,8 @@ bool BMP180IsConnected() {
int BMP180GetTemperature(double &t) { int BMP180GetTemperature(double &t) {
char status; char status;
if(!BMP180IsConnected())
return -1;
status = bmp180.startTemperature(); status = bmp180.startTemperature();
if (status != 0) if (status != 0)
{ {

View File

@ -0,0 +1,15 @@
#pragma once
#ifdef CONFIG_ENABLE_BMP280
#include "debug_sketch.h"
int BMP280GetTemperature(double &t);
int BMP280GetTempAndPressure(double &t, double &p);
int BMP280Setup();
bool BMP280IsConnected();
#else //CONFIG_ENABLE_BMP80
int BMP280GetTemperature(double &){return -1;};
int BMP280GetTempAndPressure(double &, double &){return -1;};
int BMP280Setup(){SKETCH_DEBUG_PRINTLN("BMP280 is disabled at build time"); return -1;};
bool BMP280IsConnected(){return false;};
#endif

View File

@ -0,0 +1,44 @@
#ifdef CONFIG_ENABLE_BMP280
#include "BMP280.h"
#include <Adafruit_BMP280.h>
Adafruit_BMP280 bmp;
int bmpConnected = 0;
int BMP280Setup()
{
bmpConnected = bmp.begin(BMP280_ADDRESS_ALT);
if (!bmpConnected) {
SKETCH_DEBUG_PRINTLN("Cannot connect to BMP280");
return -1;
}
/* Default settings from datasheet. */
bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, /* Operating Mode. */
Adafruit_BMP280::SAMPLING_X2, /* Temp. oversampling */
Adafruit_BMP280::SAMPLING_X16, /* Pressure oversampling */
Adafruit_BMP280::FILTER_X16, /* Filtering. */
Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */
return 0;
}
bool BMP280IsConnected()
{
return bmpConnected != 0;
}
int BMP280GetTemperature(double &t)
{
if (!BMP280IsConnected())
return -1;
t = bmp.readTemperature();
return 0;
}
int BMP280GetTempAndPressure(double &t, double &p)
{
if (!BMP280IsConnected())
return -1;
t = bmp.readTemperature();
p = bmp.readPressure()/100;
return 0;
}
#endif

View File

@ -0,0 +1,28 @@
#pragma once
typedef struct productConfig_t {
uint8_t bootMode;
char *ssid;
char *password;
char *host;
char *mqttServer;
char *mqttUser;
char *mqttPasswd;
int mqttPort;
int ip_mode;
uint32_t ip;
uint32_t gw;
uint32_t mask;
uint32_t dns;
uint32_t dns2;
uint8_t channel;
char *bssid;
uint32_t samplingPeriod;
} productConfig;
int EepromSaveConfig(productConfig &config);
int EepromSaveBootMode(uint8_t bootMode);
void EepromReadConfig(productConfig &config);
int EepromSaveBME680State(uint8_t *bsecState);
int EepromLoadBME680State(uint8_t *bsecState);

View File

@ -1,21 +1,37 @@
/* EEPROM LAYOUT /* EEPROM LAYOUT
"BOOTMODE;SSID;PASSWORD;HOSTNAME;MQTT_SERVER;MQTT_USERNAME;MQTT_PASSWD;MQTT_PORT;" "BOOTMODE;SSID;PASSWORD;HOSTNAME;MQTT_SERVER;MQTT_USERNAME;MQTT_PASSWD;MQTT_PORT;IP_CONFIG;IP;GATEWAY;NETMASK;DNS1;DNS2;WIFI_CHANNEL;WIFI_BSSID;"
BOOTMODE could be 0 for Setup, 1 for normal use, 2 for OTA BOOTMODE could be 0 for Setup, 1 for normal use, 2 for OTA
IP_CONFIG could be 0 for DHCP, 1 for static
Setup mode is trigger by setting GPIO3 to ground or at first boot Setup mode is trigger by setting GPIO3 to ground or at first boot
*/ */
#include "EEPROM.h"
#define BME680_BSEC_EEPROM_ORIG (CONFIG_EEPROM_SIZE)
int EepromSaveConfig(uint8_t bootMode, String ssid, String password, String host, String mqttServer, String mqttUser, String mqttPasswd, int mqttPort) { #if (CONFIG_EEPROM_SIZE + BSEC_MAX_STATE_BLOB_SIZE) >= SPI_FLASH_SEC_SIZE
#error "CONFIG_EEPROM_SIZE too big"
#endif
char eeprom[CONFIG_EEPROM_SIZE];
int EepromSaveConfig(productConfig &config) {
String eeprom; String eeprom;
eeprom = String(bootMode) + ";" + ssid + ";" + password + ";" + host + ";" + mqttServer + ";" + mqttUser + ";" + mqttPasswd + ";" + String(mqttPort) + ";"; eeprom = String(config.bootMode) + ";" + config.ssid + ";" + config.password + ";"
+ config.host + ";" + config.mqttServer + ";"
+ config.mqttUser + ";" + config.mqttPasswd + ";"
+ String(config.mqttPort) + ";"
+ String(config.ip_mode) + ";"
+ config.ip + ";" + config.gw + ";" + config.mask + ";"
+ config.dns + ";" + config.dns2 + ";" + config.channel + ";"
+ config.bssid + ";" + config.samplingPeriod + ";";
if (eeprom.length() > EEPROM_SIZE ) if (eeprom.length() > CONFIG_EEPROM_SIZE )
return -EMSGSIZE; return -EMSGSIZE;
SKETCH_DEBUG_PRINTLN("Saving " + eeprom); SKETCH_DEBUG_PRINTLN("Saving " + eeprom);
for (int i = 0; i < eeprom.length() && i < EEPROM_SIZE; i++) { for (uint i = 0; i < eeprom.length() && i < CONFIG_EEPROM_SIZE; i++) {
EEPROM.write(i, eeprom.charAt(i)); EEPROM.write(i, eeprom.charAt(i));
} }
@ -37,37 +53,97 @@ void readConfElement(char** element, int &i) {
do { do {
eeprom[i] = EEPROM.read(i); eeprom[i] = EEPROM.read(i);
i++; i++;
} while (i < EEPROM_SIZE && eeprom[i - 1] != ';'); } while (i < CONFIG_EEPROM_SIZE && eeprom[i - 1] != ';');
eeprom[i - 1] = '\0'; eeprom[i - 1] = '\0';
if (i >= EEPROM_SIZE) if (i >= CONFIG_EEPROM_SIZE){
SKETCH_DEBUG_PRINTLN("Looks like there is a configuration issue (too long)");
**element = '\0'; **element = '\0';
}
} }
void EepromReadConfig(uint8_t &bootMode, char **ssid, char **password, char **host, char **mqttServer, char **mqttUser, char **mqttPasswd, int &mqttPort) { void EepromReadConfig(productConfig &config) {
int i = 2; int i = 2;
uint8_t boot = EEPROM.read(0); uint8_t boot = EEPROM.read(0);
char *mqttPortString = ""; char *tmpString;
if (boot == '1') { if (boot == '1') {
bootMode = BOOTMODE_NORMAL; config.bootMode = BOOTMODE_SETUP;
} else if (boot == '2') { } else if (boot == '2') {
bootMode = BOOTMODE_OTA; config.bootMode = BOOTMODE_NORMAL;
} else if (boot == '3') {
config.bootMode = BOOTMODE_OTA;
} else { } else {
//Do not need to parse EEPROM when not configured //Do not need to parse EEPROM when not configured
bootMode = BOOTMODE_SETUP; config.bootMode = BOOTMODE_SETUP;
return; return;
} }
readConfElement(ssid, i); readConfElement(&config.ssid, i);
readConfElement(password, i); readConfElement(&config.password, i);
readConfElement(host, i); readConfElement(&config.host, i);
readConfElement(mqttServer, i); readConfElement(&config.mqttServer, i);
readConfElement(mqttUser, i); readConfElement(&config.mqttUser, i);
readConfElement(mqttPasswd, i); readConfElement(&config.mqttPasswd, i);
readConfElement(&mqttPortString, i); readConfElement(&tmpString, i);
mqttPort = atoi(mqttPortString); config.mqttPort = atoi(tmpString);
readConfElement(&tmpString, i);
config.ip_mode = atoi(tmpString);
readConfElement(&tmpString, i);
config.ip = atoll(tmpString);
readConfElement(&tmpString, i);
config.gw = atoll(tmpString);
readConfElement(&tmpString, i);
config.mask = atoll(tmpString);
readConfElement(&tmpString, i);
config.dns = atoll(tmpString);
readConfElement(&tmpString, i);
config.dns2 = atoll(tmpString);
readConfElement(&tmpString, i);
config.channel = atoi(tmpString);
readConfElement(&config.bssid, i);
readConfElement(&tmpString, i);
config.samplingPeriod = atoi(tmpString);
}
int EepromSaveBME680State(uint8_t *bsecState)
{
for (uint16_t i = BME680_BSEC_EEPROM_ORIG;
i < BME680_BSEC_EEPROM_ORIG + BSEC_MAX_STATE_BLOB_SIZE; i++) {
EEPROM.write(i + 1, bsecState[i]);
}
EEPROM.write(BME680_BSEC_EEPROM_ORIG, BSEC_MAX_STATE_BLOB_SIZE);
EEPROM.commit();
return 0;
}
int EepromLoadBME680State(uint8_t *bsecState)
{
if (EEPROM.read(BME680_BSEC_EEPROM_ORIG) == BSEC_MAX_STATE_BLOB_SIZE) {
// Existing state in EEPROM
SKETCH_DEBUG_PRINTLN("Reading BME680 state from EEPROM");
for (uint16_t i = BME680_BSEC_EEPROM_ORIG;
i < BME680_BSEC_EEPROM_ORIG + BSEC_MAX_STATE_BLOB_SIZE; i++) {
bsecState[i] = EEPROM.read(i + 1);
}
return 0;
} else {
// Erase the EEPROM with zeroes
SKETCH_DEBUG_PRINTLN("Erasing EEPROM for BME680 state");
for (uint16_t i = BME680_BSEC_EEPROM_ORIG;
i < BME680_BSEC_EEPROM_ORIG + BSEC_MAX_STATE_BLOB_SIZE + 1; i++)
EEPROM.write(i, 0);
EEPROM.commit();
return -1;
}
} }

64
WifiControlSensor/MQTT.h Normal file
View File

@ -0,0 +1,64 @@
#pragma once
//FEED have the following formats /feeds/USER/DEVICE_NAME/....
#define TEMPERATURE_FEED_FORMAT "/feeds/%s/%s/temperature"
#define PRESSURE_FEED_FORMAT "/feeds/%s/%s/pressure"
#define TEMPERATURE_DHT_FEED_FORMAT "/feeds/%s/%s/dht/temperature"
#define HUMIDITY_DHT_FEED_FORMAT "/feeds/%s/%s/dht/humidity"
#define DRY_FEED_FORMAT "/feeds/%s/%s/dry"
#define GPIO_FEED_FORMAT "/feeds/%s/%s/gpio/%d"
#define GPIO_SET_FEED_FORMAT "/feeds/%s/%s/gpio/%d/set"
#define PWM_FEED_FORMAT "/feeds/%s/%s/gpio/%d"
#define PWM_SET_FEED_FORMAT "/feeds/%s/%s/gpio/%d/set"
#define IP_FEED_FORMAT "/feeds/%s/%s/configuration/ip/addr"
#define BME680_TEMPERATURE_FEED_FORMAT "/feeds/%s/%s/bme680/temperature"
#define BME680_PRESSURE_FEED_FORMAT "/feeds/%s/%s/bme680/pressure"
#define BME680_HUMIDITY_FEED_FORMAT "/feeds/%s/%s/bme680/humidity"
#define BME680_GAZ_FEED_FORMAT "/feeds/%s/%s/bme680/gaz"
#define BME680_ALT_FEED_FORMAT "/feeds/%s/%s/bme680/alt"
#define BME680_IAQ_FEED_FORMAT "/feeds/%s/%s/bme680/iaq"
#define BME680_IAQ_ACC_FEED_FORMAT "/feeds/%s/%s/bme680/iaqAcc"
#define TELEINFO_IINST_FEED_FORMAT "/feeds/%s/%s/teleinfo/iinst"
#define TELEINFO_PAPP_FEED_FORMAT "/feeds/%s/%s/teleinfo/papp"
#define TELEINFO_BASE_FEED_FORMAT "/feeds/%s/%s/teleinfo/base"
#define SCD4X_TEMPERATURE_FEED_FORMAT "/feeds/%s/%s/scd4x/temperature"
#define SCD4X_HUMIDITY_FEED_FORMAT "/feeds/%s/%s/scd4x/humidity"
#define SCD4X_CO2_FEED_FORMAT "/feeds/%s/%s/scd4x/co2"
#ifndef CONFIG_DISABLE_MQTT
#include "Adafruit_MQTT.h"
typedef struct {uint8_t updated; int value;} gpioInfo;
struct mqttInfo {
float value;
const char *topic;
uint8_t retain;
uint8_t qos;
};
int MqttBatchPublish(std::vector<struct mqttInfo> tab, ...);
Adafruit_MQTT_Publish *MqttCreatePublisher(uint8_t qos, uint8_t retain, const char *fmt, ...);
int MqttConnect();
int MqttIsConnected();
int MqttSetup(const char *server, const char *user, const char *passwd, int port, const char * hostname);
template<typename T> int MqttPublish(Adafruit_MQTT_Publish *publisher, T value);
int MqttPublishIp(const String &ip);
void MqttCheckSubscription();
void MqttCheckIRQ();
void MqttChangeGpioValue(int gpio, int value);
void MqttChangePWMValue(int gpio, int value);
void MqttNofityIRQ(uint8_t gpio, int value);
void MqttNofity(int gpio, int value);
#else
int MqttBatchPublish(std::vector<struct mqttInfo> tab, ...){return 0;}
int MqttConnect(){return 0;}
int MqttIsConnected(){return 0;}
int MqttSetup(const char *server, const char *user, const char *passwd, int port, const char * hostname){return 0;}
template<typename T> int MqttPublish(Adafruit_MQTT_Publish *publisher, T value){return 0;}
int MqttPublishIP(const String &ip){return 0;}
void MqttCheckSubscription(){}
void MqttCheckIRQ(){}
void MqttChangeGpioValue(int gpio, int value){}
void MqttChangePWMValue(int gpio, int value){}
void MqttNofityIRQ(uint8_t gpio, int value){}
void MqttNofity(int gpio, int value){}
#endif

View File

@ -1,54 +1,108 @@
// Create an ESP8266 WiFiClient class to connect to the MQTT server. #ifndef CONFIG_DISABLE_MQTT
WiFiClient client; #include <stdarg.h>
#include "utils.h"
#include "MQTT.h"
#define MAX_PIN 15
#define MAX_GPIO_OBSERVED (MAXSUBSCRIPTIONS*2)
Adafruit_MQTT_Client *mqtt; Adafruit_MQTT_Client *mqtt;
Adafruit_MQTT_Publish *mqtt_temp; Adafruit_MQTT_Publish *mqtt_ip;
Adafruit_MQTT_Publish *mqtt_pressure; Adafruit_MQTT_Publish *mqttGpio[MAXSUBSCRIPTIONS] = {};
Adafruit_MQTT_Publish *mqttPwm[MAXSUBSCRIPTIONS] = {};
Adafruit_MQTT_Publish *mqttGpioObserved[MAX_GPIO_OBSERVED] = {};
gpioInfo mqttIRQ[MAX_PIN + 1] = {};
#define NB_ELEMENTS(x) (sizeof(x)/ sizeof(x[0])) #define FEED_MAX_SIZE 96
#define FEED_MAX_SIZE 64
#define TEMPERATURE_FEED_FORMAT "/feeds/%s/temperature" bool isMqttConfigured = false;
#define PRESSURE_FEED_FORMAT "/feeds/%s/pressure" bool useMqtts = false;
char temperatureFeed[FEED_MAX_SIZE] = {};
char pressureFeed[FEED_MAX_SIZE] = {};
// Should have less that MAXSUBSCRIPTIONS elements
// MAXSUBSCRIPTIONS is defined is Adafruit_mqtt.h
const int gpioWatched[] = {2, 13};
#define GPIO_FEED_FORMAT "/feeds/%s/gpio/%d" int MqttSetup(const char *server, const char *user, const char *passwd, int port, const char *hostname) {
#define GPIO_SET_FEED_FORMAT "/feeds/%s/gpio/%d/set" useMqtts = (port == 8883);
isMqttConfigured = server[0] != '\0';
char *mqttId; if (!isMqttConfigured)
char GPIO_FEED[MAXSUBSCRIPTIONS][FEED_MAX_SIZE] = {}; return 0;
char GPIO_SET_FEED[MAXSUBSCRIPTIONS][FEED_MAX_SIZE] = {};
Adafruit_MQTT_Publish * mqttGpio[MAXSUBSCRIPTIONS] = {}; #ifndef CONFIG_DISABLE_SSL
if (useMqtts)
mqtt = new Adafruit_MQTT_Client(new WiFiClientSecure(), server, port, user, passwd);
else
#endif
mqtt = new Adafruit_MQTT_Client(new WiFiClient(), server, port, user, passwd);
int MqttSetup(char *server, char *user, char *passwd, int port, char * hostname) { mqtt_ip = MqttCreatePublisher(0, 1, IP_FEED_FORMAT, user, hostname);
mqttId = hostname;
snprintf(temperatureFeed, FEED_MAX_SIZE, TEMPERATURE_FEED_FORMAT, mqttId);
snprintf(pressureFeed, FEED_MAX_SIZE, PRESSURE_FEED_FORMAT, mqttId);
mqtt = new Adafruit_MQTT_Client(&client, server, port, user, passwd); if (NB_ELEMENTS(gpioControlled) + NB_ELEMENTS(pwmControlled) > MAXSUBSCRIPTIONS) {
mqtt_temp = new Adafruit_MQTT_Publish(mqtt, temperatureFeed); SKETCH_DEBUG_PRINTF("Too much gpio/pwm to control\n Nb gpio %d Nb pwm %d Max is %d",
mqtt_pressure = new Adafruit_MQTT_Publish(mqtt, pressureFeed); NB_ELEMENTS(gpioControlled), NB_ELEMENTS(pwmControlled), MAXSUBSCRIPTIONS);
return -1;
}
if (NB_ELEMENTS(gpioObserved) > MAX_GPIO_OBSERVED) {
SKETCH_DEBUG_PRINTF("Too much gpio observed\n Nb gpio %d Nb is %d",
NB_ELEMENTS(gpioObserved), MAX_GPIO_OBSERVED);
return -1;
}
for (int i = 0 ; i < NB_ELEMENTS(gpioWatched) && i < MAXSUBSCRIPTIONS; i++) { for (uint i = 0 ; i < NB_ELEMENTS(gpioControlled); i++) {
snprintf(GPIO_FEED[i], FEED_MAX_SIZE, GPIO_FEED_FORMAT, mqttId, gpioWatched[i]); mqtt->subscribe(MqttCreateSubscribe(GPIO_SET_FEED_FORMAT, user, hostname, gpioControlled[i]));
snprintf(GPIO_SET_FEED[i], FEED_MAX_SIZE, GPIO_SET_FEED_FORMAT, mqttId, gpioWatched[i]); mqttGpio[i] = MqttCreatePublisher(0, 0, GPIO_FEED_FORMAT, user, hostname, gpioControlled[i]);
}
Adafruit_MQTT_Subscribe *gpioSet = new Adafruit_MQTT_Subscribe(mqtt, GPIO_SET_FEED[i]); for (uint i = 0 ; i < NB_ELEMENTS(gpioObserved) && i < MAX_GPIO_OBSERVED ; i++) {
mqtt->subscribe(gpioSet); mqttGpioObserved[i] = MqttCreatePublisher(0, 0, GPIO_FEED_FORMAT, user, hostname, gpioObserved[i]);
new HIB(gpioObserved[i], HIGH, MqttNofityIRQ , MqttNofityIRQ, NULL );
}
Adafruit_MQTT_Publish *gpio = new Adafruit_MQTT_Publish(mqtt, GPIO_FEED[i]); for (uint i = 0 ; i < NB_ELEMENTS(pwmControlled); i++) {
mqttGpio[i] = gpio; mqtt->subscribe(MqttCreateSubscribe(PWM_SET_FEED_FORMAT, user, hostname, pwmControlled[i]));
mqttPwm[i] = MqttCreatePublisher(0, 0, PWM_FEED_FORMAT, user, hostname, pwmControlled[i]);
}
return 0;
}
Adafruit_MQTT_Publish *MqttCreatePublisher( uint8_t qos, uint8_t retain, const char *fmt, ...) {
char buf[FEED_MAX_SIZE];
va_list args;
va_start (args, fmt);
vsnprintf(buf, sizeof(buf), (const char *)fmt, args);
va_end(args);
return new Adafruit_MQTT_Publish(mqtt, strdup(buf), qos, retain);
}
int MqttBatchPublish(std::vector<struct mqttInfo> tab, ...) {
if (MqttConnect()) {
SKETCH_DEBUG_PRINTLN("cannot connect to mqtt");
return -1;
}
for (auto info : tab) {
char buf[FEED_MAX_SIZE];
va_list args;
va_start (args, tab);
vsnprintf(buf, sizeof(buf), (const char *)info.topic, args);
va_end(args);
// SKETCH_DEBUG_PRINTF("publishing %f for %s\n", info.value, buf);
Adafruit_MQTT_Publish client(mqtt, buf, info.qos, info.retain);
if (!client.publish(info.value))
SKETCH_DEBUG_PRINTLN("Fail :(");
} }
return 0; return 0;
} }
Adafruit_MQTT_Subscribe *MqttCreateSubscribe(const char *fmt, ...) {
char buf[FEED_MAX_SIZE];
va_list args;
va_start (args, fmt);
vsnprintf(buf, sizeof(buf), (const char *)fmt, args);
va_end(args);
return new Adafruit_MQTT_Subscribe(mqtt, strdup(buf));
}
int MqttIsConnected() { int MqttIsConnected() {
return mqtt->connected(); return (isMqttConfigured && (mode == BOOTMODE_NORMAL)) ? mqtt->connected() : 0;
} }
// Function to connect and reconnect as necessary to the MQTT server. // Function to connect and reconnect as necessary to the MQTT server.
@ -56,6 +110,9 @@ int MqttIsConnected() {
int MqttConnect() { int MqttConnect() {
int8_t ret; int8_t ret;
if (!isMqttConfigured || mode != BOOTMODE_NORMAL)
return -1;
// Stop if already connected. // Stop if already connected.
if (mqtt->connected()) { if (mqtt->connected()) {
return 0; return 0;
@ -75,20 +132,23 @@ int MqttConnect() {
return 0; return 0;
} }
int MqttPublish(double temp, double pressure) { template<typename T> int MqttPublish(Adafruit_MQTT_Publish *publisher, T value) {
if (MqttConnect() == 0) { if (MqttConnect() == 0) {
SKETCH_DEBUG_PRINTLN("publishing !"); publisher->publish(value);
mqtt_temp->publish(temp); return 0;
mqtt_pressure->publish(pressure);
} }
return 0; return -1;
} }
int getGpioFromSubscription(Adafruit_MQTT_Subscribe *subscription) { int MqttPublishIP(const String &ip) {
char *temp = strstr(subscription->topic, "/gpio/"); return MqttPublish(mqtt_ip, ip.c_str());
}
int getGpioFromSubscription(Adafruit_MQTT_Subscribe *subscription, const char *pattern) {
char *temp = strstr(subscription->topic, pattern);
if (!temp) if (!temp)
return -1; return -1;
String gpioStr(temp + strlen("/gpio/")); String gpioStr(temp + strlen(pattern));
int idx = gpioStr.indexOf("/"); int idx = gpioStr.indexOf("/");
int gpio = gpioStr.substring(0, idx).toInt(); int gpio = gpioStr.substring(0, idx).toInt();
@ -98,36 +158,68 @@ int getGpioFromSubscription(Adafruit_MQTT_Subscribe *subscription) {
return -1; return -1;
} }
int getGpioWatchedIndex(int gpio) { void MqttNofityIRQ(uint8_t gpio, int value) {
for ( int i = 0; i < NB_ELEMENTS(gpioWatched); i++) { mqttIRQ[gpio].updated = 1;
if (gpio == gpioWatched[i]) mqttIRQ[gpio].value = value;
return i; }
void MqttNofity(int gpio, int value) {
if (MqttIsConnected()) {
int watchIdx = findIndex(gpio, gpioControlled);
if (watchIdx >= 0 ) {
mqttGpio[watchIdx]->publish(value);
} else {
watchIdx = findIndex(gpio, gpioObserved);
if (watchIdx >= 0 )
mqttGpioObserved[watchIdx]->publish(value);
}
} }
return -1;
} }
void MqttChangeGpioValue(int gpio, int value) { void MqttChangeGpioValue(int gpio, int value) {
pinMode(gpio, OUTPUT); pinMode(gpio, OUTPUT);
digitalWrite(gpio, value); digitalWrite(gpio, value);
int watchIdx = getGpioWatchedIndex(gpio); MqttNofity(gpio, value);
if (watchIdx >= 0 ) {
mqttGpio[watchIdx]->publish(value);
}
} }
void MqttCheckSubscription() { void MqttChangePWMValue(int gpio, int value) {
analogWrite(gpio, value);
MqttNofity(gpio, value);
}
void MqttCheckIRQ() {
for (uint i = 0 ; i < NB_ELEMENTS(mqttIRQ); i++) {
if (mqttIRQ[i].updated == 1) {
mqttIRQ[i].updated = 0;
MqttNofity(i, mqttIRQ[i].value);
}
}
}
void MqttCheckSubscription()
{
if (mqtt->getSubscriptionCount() == 0)
return;
if (MqttConnect() == 0) { if (MqttConnect() == 0) {
Adafruit_MQTT_Subscribe *subscription; Adafruit_MQTT_Subscribe *subscription;
while (subscription = mqtt->readSubscription(0)) { while ((subscription = mqtt->readSubscription(0))) {
int gpio = getGpioFromSubscription(subscription); int gpio = getGpioFromSubscription(subscription, "/gpio/");
SKETCH_DEBUG_PRINT("Got Subscription for gpio "); if (gpio > 0 && findIndex(gpio, gpioControlled) >= 0) {
SKETCH_DEBUG_PRINTLN(gpio); SKETCH_DEBUG_PRINTF("Got Subscription for GPIO %d\n", gpio);
if (gpio > 0 && getGpioWatchedIndex(gpio) >= 0) { char *value = (char *)subscription->lastread;
char *value = (char *) subscription->lastread; SKETCH_DEBUG_PRINTF("Receive data: %s\n", value);
SKETCH_DEBUG_PRINT("Receive data: ");
SKETCH_DEBUG_PRINTLN(value);
MqttChangeGpioValue(gpio, atoi(value)); MqttChangeGpioValue(gpio, atoi(value));
} }
gpio = getGpioFromSubscription(subscription, "/pwm/");
if (gpio > 0 && findIndex(gpio, pwmControlled) >= 0) {
SKETCH_DEBUG_PRINTF("Got Subscription for PWM %d\n", gpio);
char *value = (char *)subscription->lastread;
SKETCH_DEBUG_PRINTF("Receive data: %s\n", value);
MqttChangePWMValue(gpio, atoi(value));
}
} }
} }
} }
#endif

23
WifiControlSensor/SCD4X.h Normal file
View File

@ -0,0 +1,23 @@
#pragma once
#ifdef CONFIG_ENABLE_SCD4X
#include "debug_sketch.h"
int SCD4XGetMeasure(float &t, float &h, uint16_t &co2);
int SCD4XSetup();
bool SCD4XIsConnected();
#else
int SCD4XGetMeasure(float &, float &, uint16_t &)
{
return -1;
};
int SCD4XSetup()
{
SKETCH_DEBUG_PRINTLN("SCD4X is disabled at build time");
return -1;
};
bool SCD4XIsConnected()
{
return false;
};
#endif

View File

@ -0,0 +1,61 @@
#ifdef CONFIG_ENABLE_SCD4X
#include "SCD4X.h"
#include <Arduino.h>
#include <SensirionI2CScd4x.h>
#include <Wire.h>
SensirionI2CScd4x scd4x;
int SCD4XConnected = 0;
int SCD4XSetup()
{
Wire.begin();
scd4x.begin(Wire);
// Stop previous measurement
uint16_t error = scd4x.stopPeriodicMeasurement();
if (error) {
SKETCH_DEBUG_PRINTLN("Cannot connect to SCD4X");
return -1;
}
// Start new measurement
error = scd4x.startPeriodicMeasurement();
if (error) {
SKETCH_DEBUG_PRINTLN("Cannot start measurement for SCD4X");
return -1;
}
SCD4XConnected = 1;
return 0;
}
int SCD4XGetMeasure(float &temperature, float &humidity, uint16_t &co2)
{
// Read Measurement
bool isDataReady = false;
uint16_t error = scd4x.getDataReadyFlag(isDataReady);
if (error) {
SKETCH_DEBUG_PRINTLN("Error trying to execute getDataReadyFlag() for SCD4X ");
return -1;
}
if (!isDataReady) {
return -1;
}
error = scd4x.readMeasurement(co2, temperature, humidity);
if (error || co2 == 0) {
char errorMsg[256];
SKETCH_DEBUG_PRINT("Error with reading measurement. Error : ");
errorToString(error, errorMsg, sizeof(errorMsg));
SKETCH_DEBUG_PRINTF(" Co2: %d\n", co2);
return -1;
}
return 0;
}
bool SCD4XIsConnected()
{
return SCD4XConnected != 0;
}
#endif

View File

@ -0,0 +1,23 @@
#pragma once
#include "debug_sketch.h"
#ifdef CONFIG_ENABLE_TELEINFO
#include <LibTeleinfo.h>
int TeleinfoSetup();
int TeleinfoRetrieve(float &iinst, float &papp, float &base);
int TeleinfoRetrieve(float &iinst, float &papp, float &base,
std::vector<struct mqttInfo> &batchInfo);
#else
int TeleinfoSetup() {
SKETCH_DEBUG_PRINTLN("Teleinfo is disabled at build time");
return -1;
};
int TeleinfoRetrieve(float &, float &, float &){
return 0;
}
int TeleinfoRetrieve(float &, float &, float &, std::vector<struct mqttInfo> &)
{
return 0;
}
#endif

View File

@ -0,0 +1,77 @@
#ifdef CONFIG_ENABLE_TELEINFO
#include "Teleinfo.h"
#include <LibTeleinfo.h>
#define TELESerial Serial
TInfo tinfo;
int TeleinfoSetup()
{
TELESerial.begin(1200, SERIAL_7E1);
tinfo.init();
return 0;
}
int TeleinfoRetrieve(float &iinst, float &papp, float &base){
int c;
while ((c = TELESerial.read()) >= 0) {
tinfo.process(c);
}
ValueList *me = tinfo.getList();
if (me)
me = me->next;
while (me) {
if (strcmp(me->name, "IINST") == 0) {
iinst = atof(me->value);
}
if (strcmp(me->name, "PAPP") == 0) {
papp = atof(me->value);
}
if (strcmp(me->name, "BASE") == 0) {
float tmp = atof(me->value);
if(tmp != 0){
base = tmp;
}
}
me = me->next;
}
return 0;
}
int TeleinfoRetrieve(float &iinst, float &papp, float &base,
std::vector<struct mqttInfo> &batchInfo)
{
int c;
while ((c = TELESerial.read()) >= 0) {
tinfo.process(c);
}
ValueList *me = tinfo.getList();
if (me)
me = me->next;
while (me) {
if (strcmp(me->name, "IINST") == 0) {
iinst = atof(me->value);
batchInfo.push_back({iinst, TELEINFO_IINST_FEED_FORMAT, 0, 0});
}
if (strcmp(me->name, "PAPP") == 0) {
papp = atof(me->value);
batchInfo.push_back({papp, TELEINFO_PAPP_FEED_FORMAT, 0, 0});
}
if (strcmp(me->name, "BASE") == 0) {
float tmp = atof(me->value);
if(tmp != 0){
base = tmp;
batchInfo.push_back({base, TELEINFO_BASE_FEED_FORMAT, 0, 0});
}
}
me = me->next;
}
return 0;
}
#endif

View File

@ -1,54 +1,143 @@
#ifndef CONFIG_DISABLE_WEB
#include <ESP8266HTTPUpdateServer.h>
ESP8266HTTPUpdateServer httpUpdater;
String gpioControlHTML = "";
String pwmControlHTML = "";
void WebBuildGpioObserved(String &html) {
if (NB_ELEMENTS(gpioObserved) > 0) {
html += "<fieldset>"
"<legend>Detector</legend>";
for (uint i = 0 ; i < NB_ELEMENTS(gpioObserved) ; i++) {
html += "Sensor " + String(gpioObserved[i]) + ": " + digitalRead(gpioObserved[i]) + "<br/>";
}
html += "</fieldset>";
}
}
void WebHandleRoot() { void WebHandleRoot() {
String gpioObserved = "";
String optimiseConfig = "";
WebBuildGpioObserved(gpioObserved);
if (WiFi.status() == WL_CONNECTED) {
optimiseConfig = "<a href=\"/setupPreConfig\">Optimize Config</a><br/>";
}
server.send(200, "text/html", server.send(200, "text/html",
"<head><meta http-equiv=\"refresh\" content=\"" + String(SAMPLING_PERIODE_MS / 1000) + "\" ></head>" "<head><meta http-equiv=\"refresh\" content=\"" + String(CONFIG_SAMPLING_PERIOD_MS / 1000) + "\" ></head>"
"<h1>You are connected to " + String(hostName) + "</h1>" "<h1>You are connected to " + String(conf.host) + "</h1>"
"<fieldset>" "<fieldset>"
"<legend>Sensors</legend>" "<legend>Sensors</legend>"
"Temperature " + String(temp, 2) + "C<br/>" #if defined CONFIG_ENABLE_BMP180 || defined CONFIG_ENABLE_BMP280
"Pressure " + String(pressure, 2) + "mB<br/>" "" + ((BMP180IsConnected() || BMP280IsConnected()) ? "<h6>BMP180/280</h6>Temperature " + String(temp, 2) + "C<br/> Pressure " + String(pressure, 2) + "hPa<br/>" : "BMP180/280 Disconnected" ) + ""
"</fieldset>" #endif
"<fieldset>" #ifdef CONFIG_ENABLE_DHT
"<legend>Pump</legend>" "" + (DHTIsConnected() ? "<h6>DHT</h6>Temperature " + String(dhtTemp, 0) + "C<br/> Humidity " + String(dhtHumidity, 0) + "%<br/>" : "DHT Disconnected" ) + ""
"<a href=\"/gpio?gpio=2&amp;value=1\">Power PUMP ON</a><br/>" #endif
"<a href=\"/gpio?gpio=2&value=0\">Power PUMP OFF</a><br/>" #ifdef CONFIG_ENABLE_SCD4X
"</fieldset>" "" + (SCD4XIsConnected() ? "<h6>SCD4X</h6>Temperature " + String(SCD4xT, 0) + "C<br/> Humidity " + String(SCD4xH, 0) + "%<br/> CO2 " + String(SCD4xCo2) + "ppm<br/>" : "SCD4X Disconnected" ) + ""
"<fieldset>" #endif
#ifdef CONFIG_ENABLE_BME680
"" + (BME680IsConnected() ? "<h6>BME680</h6>Temperature " + String(bme680T, 2) + "C<br/> Pressure " + String(bme680P, 2) + "hPa<br/> Humidity " + String(bme680H, 2) + "%<br/> Gaz " + String(bme680G, 2) + "kOhm<br/>" : "BME680 Disconnected" ) + ""
#endif
#ifdef CONFIG_BME680_BSEC_ENABLE
"" + (BME680BSECIsConnected() ? "<h6>BME680 BSEC</h6>Temperature " + String(bme680BSECT, 2) + "C<br/> Pressure " + String(bme680BSECP, 2) + "hPa<br/> Humidity " + String(bme680BSECH, 2) + "%<br/> Indoor Air Quality " + String(bme680BSECIaq, 2) + "/500<br/> IAQ Accuraccy" + String(bme680BSECIaqAcc) + "/3<br/>": "BME680 Disconnected" ) + ""
#endif
#ifdef CONFIG_ENABLE_DRY_SENSOR
"Dryness " + String((dryness * 100) / 1024) + "%<br/>"
#endif
#ifdef CONFIG_ENABLE_TELEINFO
"<h6>Power Consumption</h6> Base " + String(teleBase, 2) +"Kwh<br/> AC Power " + telePapp +"VA<br/> Instant Current" + teleIinst +"A<br/>"
#endif
"</fieldset>" + gpioControlHTML + gpioObserved + pwmControlHTML + "<fieldset>"
"<legend>Settings</legend>" "<legend>Settings</legend>"
"<a href=\"/setup\">Enter Setup</a><br/>" "<a href=\"/setup\">Enter Setup</a><br/>"
"<a href=\"/otamode\">Put device in OTA mode</a><br/>" "<a href=\"/upload\">Update firmware</a><br/>" + optimiseConfig +
"MQTT Status: " + (MqttIsConnected() ? "Connected" : "Disconnected") + "<br/>" "MQTT Status: " + (MqttIsConnected() ? "Connected" : "Disconnected") + "<br/>"
"BMP 180 (Temp+Pression) Status: " + (BMP180IsConnected() ? "Connected" : "Disconnected") + "<br/>" "Wifi Strength: " + WiFi.RSSI() + "dBm<br/>"
"Free space: " + ESP.getFreeSketchSpace() + "<br/>" "Free space: " + ESP.getFreeSketchSpace() + "<br/>"
"Free heap: " + ESP.getFreeHeap() + "<br/>" "Free heap: " + ESP.getFreeHeap() + "<br/>"
"Build the " + __DATE__ + " at " + __TIME__ + "<br/>"
"</fieldset>" "</fieldset>"
); );
} }
void WebHandleSetup() { void WebSendError(const char *error) {
uint8_t mode; server.send(500, "text/plain", error);
char *confSsid = ""; }
char *confPassword = "";
char *confHost = ""; void WebBuildSSIDList(String &datalist) {
char *mqttServer = ""; int n = WiFi.scanNetworks();
char *mqttUser = ""; datalist = "<datalist id=\"scan_ssid\">";
char *mqttPasswd = ""; // sort by RSSI
int mqttPort = 1883; int indices[n];
for (int i = 0; i < n; i++) {
indices[i] = i;
}
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (WiFi.RSSI(indices[j]) > WiFi.RSSI(indices[i])) {
std::swap(indices[i], indices[j]);
}
}
}
for (int i = 0; i < n; ++i) {
datalist += "<option value=\"" + WiFi.SSID(indices[i]) + "\">";
}
datalist += "</datalist>";
}
void WebHandleSetupPreConfig() {
conf.bssid = strdup( WiFi.BSSIDstr().c_str());
conf.channel = WiFi.channel();
conf.ip_mode = 1;
conf.ip = WiFi.localIP();
conf.mask = WiFi.subnetMask();
conf.gw = WiFi.gatewayIP();
conf.dns = WiFi.dnsIP();
conf.dns2 = WiFi.dnsIP(1);
WebHandleSetup();
}
void WebHandleSetup() {
String ssidlist;
WebBuildSSIDList(ssidlist);
String dhcpChecked = conf.ip_mode == 0 ? "checked" : "";
String staticChecked = conf.ip_mode == 1 ? "checked" : "";
EepromReadConfig(mode, &confSsid, &confPassword, &confHost, &mqttServer, &mqttUser, &mqttPasswd, mqttPort);
server.send(200, "text/html", "<form action=\"/save\" method=\"get\">" server.send(200, "text/html", "<form action=\"/save\" method=\"get\">"
"<fieldset>" "<fieldset>"
"<legend>Wifi configuration:</legend>" "<legend>Wifi configuration:</legend>"
"<div><label for=\"ssid\">Wifi SSID :</label> <br/><input type=\"text\" name=\"ssid\" value=\"" + String(confSsid) + "\" /></div>" "<div><label for=\"ssid\">Wifi SSID: </label> <br/><input list=\"scan_ssid\" type=\"text\" name=\"ssid\" value=\"" + String(conf.ssid) + "\" /></div>"
"<div><label for=\"password\">Wifi Password :</label><br/><input type=\"password\" name=\"password\" /> </div>" "" + ssidlist + ""
"<div><label for=\"host\">Hostname :</label><br/><input type=\"text\" name=\"host\" value=\"" + String(confHost) + "\" /> </div>" "<div><label for=\"password\">Wifi Password: </label><br/><input type=\"password\" name=\"password\" style=\"border-color:red\" value=\"" + String(conf.password) + "\"/> </div>"
"<div><label for=\"host\">Hostname: </label><br/><input type=\"text\" name=\"host\" value=\"" + String(conf.host) + "\" /> </div>"
"<div><label for=\"channel\">Channel (0 for auto): </label><br/><input type=\"text\" name=\"channel\" value=\"" + String(conf.channel) + "\" /> </div>"
"<div><label for=\"bssid\">BSSID (Empty for auto): </label><br/><input type=\"text\" name=\"bssid\" value=\"" + String(conf.bssid) + "\" /> </div>"
"</fieldset>"
"<fieldset>"
"<legend>IP Configuration</legend>"
"<div><input type=\"radio\" name=\"ip_config\" value=\"0\" " + dhcpChecked + ">DHCP <input type=\"radio\" name=\"ip_config\" value=\"1\" " + staticChecked + ">Static</div>"
"<div><label for=\"ip\">Ip :</label><br/><input type=\"text\" name=\"ip\" value=\"" + (conf.ip == 0 ? WiFi.localIP().toString() : IPAddress(conf.ip).toString()) + "\" /> </div>"
"<div><label for=\"gw\">Gateway :</label><br/><input type=\"text\" name=\"gw\" value=\"" + (conf.gw == 0 ? WiFi.gatewayIP().toString() : IPAddress(conf.gw).toString()) + "\" /> </div>"
"<div><label for=\"mask\">Netmask :</label><br/><input type=\"text\" name=\"mask\" value=\"" + (conf.mask == 0 ? WiFi.subnetMask().toString() : IPAddress(conf.mask).toString()) + "\" /> </div>"
"<div><label for=\"mask\">DNS :</label><br/><input type=\"text\" name=\"dns\" value=\"" + (conf.dns == 0 ? (WiFi.dnsIP().isSet() ? WiFi.dnsIP().toString():"") : IPAddress(conf.dns).toString()) + "\" /> </div>"
"<div><label for=\"mask\">DNS2 :</label><br/><input type=\"text\" name=\"dns2\" value=\"" + (conf.dns2 == 0 ? (WiFi.dnsIP(1).isSet() ? WiFi.dnsIP(1).toString():"") : IPAddress(conf.dns2).toString()) + "\" /> </div>"
"</fieldset>" "</fieldset>"
"<fieldset>" "<fieldset>"
"<legend>MQTT:</legend>" "<legend>MQTT:</legend>"
"<div><label for=\"mqttServer\">Server :</label><br/><input type=\"text\" name=\"mqttServer\" value=\"" + String(mqttServer) + "\" /> </div>" "<div><label for=\"mqttServer\">Server :</label><br/><input type=\"text\" name=\"mqttServer\" value=\"" + String(conf.mqttServer) + "\" /> </div>"
"<div><label for=\"mqttUser\">Username :</label><br/><input type=\"text\" name=\"mqttUser\" value=\"" + String(mqttUser) + "\" /> </div>" "<div><label for=\"mqttUser\">Username :</label><br/><input type=\"text\" name=\"mqttUser\" value=\"" + String(conf.mqttUser) + "\" /> </div>"
"<div><label for=\"mqttPasswd\">Password :</label><br/><input type=\"password\" name=\"mqttPasswd\" /> </div>" "<div><label for=\"mqttPasswd\">Password :</label><br/><input type=\"password\" name=\"mqttPasswd\" style=\"border-color:red\" value=\"" + String(conf.mqttPasswd) + "\" /> </div>"
"<div><label for=\"mqttPort\">Port :</label><br/><input type=\"text\" name=\"mqttPort\" value=\"" + String(mqttPort) + "\" /> </div>" "<div><label for=\"mqttPort\">Port :</label><br/><input type=\"text\" name=\"mqttPort\" value=\"" + String(conf.mqttPort) + "\" /> (8883 for secure Mqtts) </div>"
"</fieldset>"
"<fieldset>"
"<legend>Sensor:</legend>"
"<div><label for=\"samplingPeriod\">Sampling Period (ms): </label><br/><input type=\"text\" name=\"samplingPeriod\" value=\"" + String(conf.samplingPeriod) + "\" /> </div>"
"</fieldset>" "</fieldset>"
"<div class=\"button\"> <button type=\"submit\">Save</button></div>" "<div class=\"button\"> <button type=\"submit\">Save</button></div>"
"</form>"); "</form>");
@ -64,34 +153,90 @@ void WebHandleGpio() {
server.send(200, "text/html", "<h1>GPIO" + server.arg("gpio") + " changed to " + server.arg("value") + "</h1>"); server.send(200, "text/html", "<h1>GPIO" + server.arg("gpio") + " changed to " + server.arg("value") + "</h1>");
} }
void WebHandleSave() { void WebHandlePWM() {
String password; if (!server.hasArg("gpio") || !server.hasArg("value")) {
String ssid;
String hostName;
String mqttServer;
String mqttUser;
String mqttPasswd;
if (!server.hasArg("ssid") || !server.hasArg("password") || !server.hasArg("host") || !server.hasArg("mqttServer") || !server.hasArg("mqttUser") || !server.hasArg("mqttPasswd") || !server.hasArg("mqttPort") ) {
server.send(500, "text/plain", "Bad arguments\r\n"); server.send(500, "text/plain", "Bad arguments\r\n");
return; return;
} }
if (EepromSaveConfig(BOOTMODE_NORMAL, server.arg("ssid"), server.arg("password"), server.arg("host"), server.arg("mqttServer"), server.arg("mqttUser"), server.arg("mqttPasswd"), server.arg("mqttPort").toInt()) < 0) { MqttChangePWMValue(server.arg("gpio").toInt(), server.arg("value").toInt());
server.send(500, "text/plain", "Cannot Save Credentials (Too long ?Contains \";\"?)\r\n"); server.send(200, "text/html", "<h1>PWM" + server.arg("gpio") + " changed to " + server.arg("value") + "</h1>");
}
boolean WebSetIp(IPAddress &addr, const char *id, const char *error) {
if (server.arg(id) != "" && !addr.fromString(server.arg(id).c_str())) {
WebSendError(error);
return false;
}
return true;
}
void WebHandleSave() {
IPAddress ip;
IPAddress gw;
IPAddress mask;
IPAddress dns;
IPAddress dns2;
if (!server.hasArg("ssid") || !server.hasArg("password") || !server.hasArg("host")
|| !server.hasArg("mqttServer") || !server.hasArg("mqttUser") || !server.hasArg("mqttPasswd")
|| !server.hasArg("mqttPort") || !server.hasArg("ip_config") || !server.hasArg("ip")
|| !server.hasArg("gw") || !server.hasArg("mask") || !server.hasArg("dns")
|| !server.hasArg("dns2") || !server.hasArg("channel") || !server.hasArg("bssid") || !server.hasArg("samplingPeriod")) {
server.send(500, "text/plain", "Bad arguments\r\n");
return; return;
} }
server.send(200, "text/html", "<h1>Configuration Saved</h1><br/>"
"<a href=\"/reboot\">Reboot</a><br/>"); //Check Ip configuration
if (server.arg("ip_config").toInt() == 1) {
if (!WebSetIp(ip, "ip", "Incorrect IP") || !WebSetIp(gw, "gw", "Incorrect Gateway") || !WebSetIp(mask, "mask", "Incorrect NetMask") ||
!WebSetIp(dns, "dns", "Incorrect DNS") || !WebSetIp(dns2, "dns2", "Incorrect DNS2")) {
server.send(500, "text/plain", "Bad arguments\r\n");
return;
}
}
productConfig newConf = {BOOTMODE_NORMAL,
strdup(server.arg("ssid").c_str()),
strdup(server.arg("password").c_str()),
strdup(server.arg("host").c_str()),
strdup(server.arg("mqttServer").c_str()),
strdup(server.arg("mqttUser").c_str()),
strdup(server.arg("mqttPasswd").c_str()),
server.arg("mqttPort").toInt(),
server.arg("ip_config").toInt(),
static_cast<uint32_t>(ip),
static_cast<uint32_t>(gw),
static_cast<uint32_t>(mask),
static_cast<uint32_t>(dns),
static_cast<uint32_t>(dns2),
static_cast<uint8_t>(server.arg("channel").toInt()),
strdup(server.arg("bssid").c_str()),
static_cast<uint32_t>(server.arg("samplingPeriod").toInt())};
if (EepromSaveConfig(newConf) < 0) {
WebSendError("Cannot Save configuration ( Credentials too long ?Contains \";\"?)\r\n");
return;
}
samplingPeriod = newConf.samplingPeriod;
if (WiFi.softAPIP() != IPAddress((uint32_t)0)) {
//In STA mode, we can test the AP connection
WiFi.begin(server.arg("ssid").c_str(), server.arg("password").c_str());
server.send(200, "text/html", "<h1>Configuration Saved</h1><br/>"
"<a href=\"/wifiStatus\">Check Wifi Configuration</a><br/>"
"<a href=\"/reboot\">Reboot</a><br/>");
} else {
server.send(200, "text/html", "<h1>Configuration Saved</h1><br/>"
"<a href=\"/reboot\">Reboot</a><br/>");
}
} }
void WebHandleOTA() { void WebHandleOTA() {
SKETCH_DEBUG_PRINTLN("Boot mode Set to OTA"); SKETCH_DEBUG_PRINTLN("Activating OTA mode");
EepromSaveBootMode(BOOTMODE_OTA); server.send(200, "text/html", "<h1>Setting OTA mode</h1><br/>"
server.send(200, "text/html", "<h1>OTA Mode set</h1><br/>" "Web ui will be disabled<br/>");
"You can reboot now" mode = BOOTMODE_OTA;
"<a href=\"/reboot\">Reboot</a><br/>"); OTASetup();
} }
void WebHandleNotFound() { void WebHandleNotFound() {
@ -115,17 +260,99 @@ void WebHandleReboot() {
ESP.restart(); ESP.restart();
} }
void WebSetupServer(int bootmode) { String statusToString(wl_status_t status) {
switch (status) {
case WL_IDLE_STATUS: return String("Idle");
case WL_NO_SSID_AVAIL: return String("Wifi not found");
case WL_CONNECTED: return String("Connected");
case WL_CONNECT_FAILED: return String("Connection failed (Wrong password ?)");
case WL_CONNECTION_LOST: return String("Connection Lost");
case WL_DISCONNECTED: return String("Connecting");
default: return String(status);
}
}
void WebHandleWifiStatus() {
String message;
if (WiFi.status() == WL_DISCONNECTED)
message += "<head><meta http-equiv=\"refresh\" content=\"1\" ></head>";
message += "<h1>Wifi Connection Status</h1><br/>";
message += "Connection to ";
message += WiFi.SSID();
message += ":<br/>";
message += statusToString(WiFi.status());
message += "<br/>";
if (mode == BOOTMODE_SETUP && WiFi.status() == WL_CONNECTED) {
message += "Wifi correctly setup! You can reboot now<br/>";
message += "<a href=\"/reboot\">Reboot</a><br/>";
}
if (WiFi.status() == WL_CONNECT_FAILED || WiFi.status() == WL_NO_SSID_AVAIL) {
message += "Try to reconfigure you WiFi details<br/>";
message += "<a href=\"/setup\">Enter Setup</a><br/>";
}
server.send(200, "text/html", message);
}
void WebBuildGpioControl() {
if (NB_ELEMENTS(gpioControlled) > 0) {
gpioControlHTML += "<fieldset>"
"<legend>Relay</legend>";
for (uint i = 0 ; i < NB_ELEMENTS(gpioControlled) ; i++) {
gpioControlHTML += "Relay " + String(gpioControlled[i]) + " " + "<a href=\"/gpio?gpio=" + String(gpioControlled[i]) + "&amp;value=1\">ON</a>/";
gpioControlHTML += "<a href=\"/gpio?gpio=" + String(gpioControlled[i]) + "&amp;value=0\">OFF</a><br/>";
}
gpioControlHTML += "</fieldset>";
}
}
void WebBuildPwmControl() {
if (NB_ELEMENTS(pwmControlled) > 0) {
pwmControlHTML += "<fieldset>"
"<legend>PWM</legend>";
for (uint i = 0 ; i < NB_ELEMENTS(pwmControlled) ; i++) {
pwmControlHTML += "PWM " + String(pwmControlled[i]) + "<br/>";
pwmControlHTML += "<input type=\"range\" min=\"0\" max=\"1023\""
"style=\"background:#eee\""
"onChange=\"setPWM(this.value," + String(pwmControlled[i]) + ")\" />";
}
pwmControlHTML += "<script type=\"text/javascript\">"
"function setPWM(newValue, gpio){"
" var xmlHttp = new XMLHttpRequest();"
" xmlHttp.open( \"GET\", \"/pwm?gpio=\"+ gpio + \"&value=\" + newValue, true );" // false for synchronous request
" xmlHttp.send( null );}"
"</script>";
pwmControlHTML += "</fieldset>";
}
}
void WebSetupServer(int ) {
WebBuildGpioControl();
WebBuildPwmControl();
server.on("/", WebHandleRoot); server.on("/", WebHandleRoot);
server.on("/setupPreConfig", WebHandleSetupPreConfig);
server.on("/setup", WebHandleSetup); server.on("/setup", WebHandleSetup);
server.on("/save", WebHandleSave); server.on("/save", WebHandleSave);
server.on("/gpio", WebHandleGpio); server.on("/gpio", WebHandleGpio);
server.on("/pwm", WebHandlePWM);
server.on("/otamode", WebHandleOTA); server.on("/otamode", WebHandleOTA);
server.on("/reboot", WebHandleReboot); server.on("/reboot", WebHandleReboot);
server.on("/wifiStatus", WebHandleWifiStatus);
server.onNotFound(WebHandleNotFound); server.onNotFound(WebHandleNotFound);
httpUpdater.setup(&server, "/upload");
server.begin(); server.begin();
SKETCH_DEBUG_PRINTLN("HTTP server started"); SKETCH_DEBUG_PRINTLN("HTTP server started");
} }
#else
void WebHandleRoot() {}
void WebHandleSetupPreConfig() {}
void WebHandleSetup() {}
void WebHandleGpio() {}
void WebHandleSave() {}
void WebHandleOTA() {}
void WebHandleNotFound() {}
void WebSetupServer(int bootmode) {}
#endif

View File

@ -1,17 +1,34 @@
/* --------------------- CONFIG ---------------------------------- */
/* Adapt this sketch to your needs by modifying the config_device.h*/
/* --------------------- GPIO ------------------------------------ */
/* Generic GPIO Control by HTTP REST interface */ /* Generic GPIO Control by HTTP REST interface */
/* Modify GPIO by accessing DEVICE_IP/gpio?gpio=[GPIO]&value=[0|1] */ /* Modify GPIO by accessing DEVICE_IP/gpio?gpio=[GPIO]&value=[0|1] */
/* -------------------- SETUP ------------------------------------ */
/* At first boot it creates a WiFi access point */ /* At first boot it creates a WiFi access point */
/* and provide a web server on it, so you can configure Wifi ssid */ /* and provide a web server on it, so you can configure Wifi ssid */
/* Wifi passwd, and a mDNS hostname */ /* Wifi passwd, and a mDNS HOSTNAME and a mqtt server */
/* In this mode, device will be available at 192.168.4.1 */ /* In this mode, device will be available at 192.168.4.1 */
/* --------------------- OTA ------------------------------------- */
/* Device can also be put in OTA Mode: In this case, if you have */ /* Device can also be put in OTA Mode: In this case, if you have */
/* a little flash (512K), it better to disable SPIFFS in */ /* a little flash (512K), it better to disable SPIFFS in */
/* "Flash Size" Menu. Use espota.py to upload OTA */ /* "Flash Size" Menu to save some place for the sketch to upload */
/* Use espota.py to upload OTA */
/* After passing in OTA mode, next boot will be in setup mode */ /* After passing in OTA mode, next boot will be in setup mode */
/* --------------------- BMP180 -----------------------------------*/
/* if BMP180 is available temperature will be published by mqtt */
/* and on web server interface */
/* --------------------- MQTT ------------------------------------ */
/* Send information to mqtt server configured in the setup mode */
/* GPIO value configured in config_device.h can be get by */
/* subscribing to /feeds/MQTTUSER/[HOSTNAME]/gpio/[GPIO] and */
/* modified by publishin to */
/* /feeds/MQTTUSER/[HOSTNAME]/gpio/[GPIO]/set */
/* BMP180 will be published to /feeds/[HOSTNAME]/temperature and */
/* /feeds/[HOSTNAME]/pressure */
/* To Use GPIO 3 And 1, uncomment #define ENABLE_EXTRA_GPIO */
/* but Serial will be available on GPIO 15 and 13 */
#include <vector>
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <WiFiClient.h> #include <WiFiClient.h>
#include <ESP8266WebServer.h> #include <ESP8266WebServer.h>
@ -19,38 +36,55 @@
#include <EEPROM.h> #include <EEPROM.h>
#include <ArduinoOTA.h> #include <ArduinoOTA.h>
#include <errno.h> #include <errno.h>
#include <HIB.h>
#define ENABLE_BMP180 #include "config.h"
#define SKETCH_DEBUG #include "utils.h"
#include "debug_sketch.h" #include "debug_sketch.h"
#include "BMP180.h" #include "BMP180.h"
#include "BMP280.h"
#include "BME680.h"
#include "BME680_BSEC.h"
#include "sensor_DHT.h"
#include "dry_sensor.h"
#include "MQTT.h"
#include "Adafruit_MQTT.h" #include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h" #include "Adafruit_MQTT_Client.h"
#include "EEPROM.h"
#include "Teleinfo.h"
#include "SCD4X.h"
//#define ENABLE_EXTRA_GPIO extern "C" {
#include <user_interface.h>
}
#define EEPROM_SIZE 256
char eeprom[EEPROM_SIZE];
#define WEB_DELAY_MS 100 #define BOOTMODE_SETUP 1
#define SAMPLING_PERIODE_MS 60000 #define BOOTMODE_NORMAL 2
#define BOOTMODE_OTA 3
/* I2C pin used*/
#define SDA 12
#define SCL 14
#define BOOTMODE_SETUP 0
#define BOOTMODE_NORMAL 1
#define BOOTMODE_OTA 2
double temp, pressure; double temp, pressure;
float dhtTemp, dhtHumidity;
float bme680T, bme680P, bme680H, bme680G, bme680A;
float bme680BSECT, bme680BSECP, bme680BSECH, bme680BSECIaq, bme680BSECIaqAcc;
float teleIinst, telePapp, teleBase;
float SCD4xT, SCD4xH;
uint16_t SCD4xCo2;
int dryness;
uint8_t mode; uint8_t mode;
char *hostName = ""; int reconfig = 0;
productConfig conf = {BOOTMODE_SETUP, NULL, NULL, NULL, NULL, NULL, NULL, 1883, 0, 0, 0, 0, 0, 0, 0, NULL, CONFIG_SAMPLING_PERIOD_MS};
// Should have less that MAXSUBSCRIPTIONS elements
// MAXSUBSCRIPTIONS is defined is Adafruit_mqtt.h
const int gpioControlled[] = CONFIG_CONTROLLED_GPIO;
const int gpioObserved[] = CONFIG_OBSERVED_GPIO;
const int pwmControlled[] = CONFIG_CONTROLLED_PWM;
uint samplingPeriod = CONFIG_SAMPLING_PERIOD_MS;
uint nbCycle = UINT_MAX - 1;
/* Set these to your desired credentials. */ /* Set these to your desired credentials. */
const char *ssid = "ESPConfigurator"; const char *ssid = CONFIG_SSID_NAME;
ESP8266WebServer server(80); ESP8266WebServer server(80);
@ -63,43 +97,77 @@ void WebHandleOTA();
void WebHandleNotFound(); void WebHandleNotFound();
void WebSetupServer(int bootmode); void WebSetupServer(int bootmode);
/* EEPROM decl */
int EepromSaveConfig(uint8_t bootMode, String ssid, String password, String host, String mqttServer, String mqttUser, String mqttpasswd, int mqttPort);
int EepromSaveBootMode(uint8_t bootMode);
void EepromReadConfig(uint8_t &bootMode, char **ssid, char **password, char **host, char **mqttServer, char **mqttUser, char **mqttPasswd, int &mqttPort);
/* MQTT decl */ #ifdef CONFIG_SETUP_BUTTON
int MqttConnect(); void onLongButtonPressed(uint8_t pin) {
int MqttIsConnected(); if (pin == CONFIG_SETUP_BUTTON) {
int MqttSetup(char *server, char *user, char *passwd, int port, char * hostname); reconfig = 1;
int MqttPublish(double temp, double pressure); SKETCH_DEBUG_PRINTLN("Putting device in setup mode");
void MqttCheckSubscription(); mode = BOOTMODE_SETUP;
void MqttChangeGpioValue(int gpio, int value); WiFi.disconnect();
void WifiSetup(int bootmode, int forceSetup, char *confSsid, char *confPassword, char *confHost) {
IPAddress myIP;
if (bootmode == BOOTMODE_SETUP || forceSetup) {
SKETCH_DEBUG_PRINTLN("Configuring access point...");
/* You can set a password to the AP here */
WiFi.softAP(ssid); WiFi.softAP(ssid);
}
}
#endif
void WifiSetup(productConfig conf) {
IPAddress myIP;
int connectionTry = 0;
if (mode == BOOTMODE_SETUP) {
SKETCH_DEBUG_PRINTLN("Configuring access point: " CONFIG_SSID_NAME);
/* You can set a password to the AP here */
WiFi.softAP(CONFIG_SSID_NAME);
myIP = WiFi.softAPIP(); myIP = WiFi.softAPIP();
} else { } else {
//Disable previous AP mode
WiFi.softAPdisconnect(true);
SKETCH_DEBUG_PRINTLN("Connecting to Wifi..."); SKETCH_DEBUG_PRINTLN("Connecting to Wifi...");
WiFi.begin(confSsid, confPassword); if (conf.ip_mode == 1) {
while (WiFi.status() != WL_CONNECTED) { SKETCH_DEBUG_PRINTLN("Use static ip configuration");
delay(500); WiFi.config(IPAddress(conf.ip), IPAddress(conf.gw), IPAddress(conf.mask), IPAddress(conf.dns), IPAddress(conf.dns2));
SKETCH_DEBUG_PRINT("."); }
uint8_t *bssidConf = NULL;
uint8_t bssid[6];
if (conf.bssid[0] != '\0') {
String bssidStr = conf.bssid;
bssid[0] = strtoul(bssidStr.substring(0, 2).c_str(), NULL, 16);
bssid[1] = strtoul(bssidStr.substring(3, 5).c_str(), NULL, 16);
bssid[2] = strtoul(bssidStr.substring(6, 8).c_str(), NULL, 16);
bssid[3] = strtoul(bssidStr.substring(9, 11).c_str(), NULL, 16);
bssid[4] = strtoul(bssidStr.substring(12, 14).c_str(), NULL, 16);
bssid[5] = strtoul(bssidStr.substring(15, 17).c_str(), NULL, 16);
SKETCH_DEBUG_PRINTF("Using BSSID: %02x:%02x:%02x:%02x:%02x:%02x\n", bssid[5], bssid[4], bssid[3], bssid[2], bssid[1], bssid[0]);
bssidConf = bssid;
} }
SKETCH_DEBUG_PRINTLN("");
SKETCH_DEBUG_PRINTLN("WiFi connected");
if (!MDNS.begin(confHost)) { SKETCH_DEBUG_PRINTF("Using channel %u (0==auto)\n", conf.channel );
SKETCH_DEBUG_PRINTLN("Error setting up MDNS responder!"); WiFi.begin(conf.ssid, conf.password, conf.channel, bssidConf);
while (1) { while (WiFi.status() != WL_CONNECTED) {
delay(1000); delay(50);
SKETCH_DEBUG_PRINT(".");
if (reconfig == 1) {
reconfig = 0;
return;
} }
if (connectionTry == 120) {
SKETCH_DEBUG_PRINTLN("Cannot connect to wifi. Try without BSSID and channel");
WiFi.begin(conf.ssid, conf.password);
}
connectionTry++;
} }
SKETCH_DEBUG_PRINTLN("mDNS responder started"); SKETCH_DEBUG_PRINTF("\nWiFi connected\n");
#ifdef CONFIG_ENABLE_MDNS
if (!MDNS.begin(conf.host)) {
SKETCH_DEBUG_PRINTLN("Error setting up MDNS responder!");
} else {
SKETCH_DEBUG_PRINTLN("mDNS responder started");
#ifndef CONFIG_DISABLE_WEB
//Needed for OTA by HTTP
MDNS.addService("http", "tcp", 80);
#endif
}
#endif
myIP = WiFi.localIP(); myIP = WiFi.localIP();
} }
@ -108,6 +176,7 @@ void WifiSetup(int bootmode, int forceSetup, char *confSsid, char *confPassword,
} }
void OTASetup() { void OTASetup() {
#ifndef CONFIF_DISABLE_OTA
// Port defaults to 8266 // Port defaults to 8266
// ArduinoOTA.setPort(8266); // ArduinoOTA.setPort(8266);
@ -117,115 +186,214 @@ void OTASetup() {
// No authentication by default // No authentication by default
// ArduinoOTA.setPassword((const char *)"123"); // ArduinoOTA.setPassword((const char *)"123");
//Disable OTA mode to avoid forever loop
//Force BOOTMODE_SETUP in case eeprom layout have changed
EepromSaveBootMode(BOOTMODE_SETUP);
ArduinoOTA.onStart([]() { ArduinoOTA.onStart([]() {
SKETCH_DEBUG_PRINTLN("Start"); SKETCH_DEBUG_PRINTLN("Start");
}); });
ArduinoOTA.onEnd([]() { ArduinoOTA.onEnd([]() {
SKETCH_DEBUG_PRINTLN("\nEnd"); SKETCH_DEBUG_PRINTLN("\nEnd");
//Force BOOTMODE_SETUP in case eeprom layout have changed
EepromSaveBootMode(BOOTMODE_SETUP);
}); });
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
SKETCH_DEBUG_PRINTF("Progress: %u%%\r", (progress / (total / 100))); SKETCH_DEBUG_PRINTF("Progress: %u%%\n", (progress / (total / 100)));
}); });
ArduinoOTA.onError([](ota_error_t error) { ArduinoOTA.onError([](ota_error_t error) {
SKETCH_DEBUG_PRINTF("Error[%u]: ", error); SKETCH_DEBUG_PRINTF("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR){ SKETCH_DEBUG_PRINTLN("Auth Failed");} if (error == OTA_AUTH_ERROR) {
else if (error == OTA_BEGIN_ERROR){ SKETCH_DEBUG_PRINTLN("Begin Failed");} SKETCH_DEBUG_PRINTLN("Auth Failed");
else if (error == OTA_CONNECT_ERROR){ SKETCH_DEBUG_PRINTLN("Connect Failed");} }
else if (error == OTA_RECEIVE_ERROR){ SKETCH_DEBUG_PRINTLN("Receive Failed");} else if (error == OTA_BEGIN_ERROR) {
else if (error == OTA_END_ERROR){ SKETCH_DEBUG_PRINTLN("End Failed");} SKETCH_DEBUG_PRINTLN("Begin Failed");
}
else if (error == OTA_CONNECT_ERROR) {
SKETCH_DEBUG_PRINTLN("Connect Failed");
}
else if (error == OTA_RECEIVE_ERROR) {
SKETCH_DEBUG_PRINTLN("Receive Failed");
}
else if (error == OTA_END_ERROR) {
SKETCH_DEBUG_PRINTLN("End Failed");
}
}); });
ArduinoOTA.begin(); ArduinoOTA.begin();
SKETCH_DEBUG_PRINTLN("Ready"); SKETCH_DEBUG_PRINTLN("Ready");
SKETCH_DEBUG_PRINT("IP address: "); SKETCH_DEBUG_PRINTF("IP address: ");
SKETCH_DEBUG_PRINTLN(WiFi.localIP()); SKETCH_DEBUG_PRINTLN(WiFi.localIP());
SKETCH_DEBUG_PRINT("Free Space: "); SKETCH_DEBUG_PRINTF("Free Space: %d\n", ESP.getFreeSketchSpace());
SKETCH_DEBUG_PRINTLN(ESP.getFreeSketchSpace()); #endif
} }
void setup() { void setup()
{
#ifdef CONFIG_SETUP_BUTTON
new HIB(CONFIG_SETUP_BUTTON, HIGH, NULL, NULL, onLongButtonPressed);
#endif
pinMode(3, OUTPUT); pinMode(3, OUTPUT);
char *confSsid;
char *confPassword;
char *confHost;
char *mqttServer;
char *mqttUser;
char *mqttPasswd;
int mqttPort;
delay(1000); delay(1000);
SKETCH_DEBUG_INIT(115200); SKETCH_DEBUG_INIT(115200);
SKETCH_DEBUG_PRINTLN(); SKETCH_DEBUG_PRINTLN();
// Get GPIO 3 Status // Get GPIO 3 Status
Serial.swap(); //Switch Serial on GPIO 13 & 15 #if CONFIG_SERIAL_SHOULD_SWAP
pinMode(3, INPUT_PULLUP); SKETCH_DEBUG_PRINTLN("SWAP UART");
int txStatus = digitalRead(3); Serial.swap(); // Switch Serial on GPIO 13 & 15
#ifndef ENABLE_EXTRA_GPIO #endif
pinMode(CONFIG_SETUP_GPIO, INPUT_PULLUP);
int txStatus = digitalRead(CONFIG_SETUP_GPIO);
#if !defined(CONFIG_ENABLE_EXTRA_GPIO) && CONFIG_SERIAL_SHOULD_SWAP
Serial.swap(); // Switch back on GPIO 1 & 3 Serial.swap(); // Switch back on GPIO 1 & 3
SKETCH_DEBUG_PRINTLN("SWAP UART");
#endif #endif
EEPROM.begin(EEPROM_SIZE); EEPROM.begin(CONFIG_EEPROM_SIZE);
EepromReadConfig(mode, &confSsid, &confPassword, &confHost, &mqttServer, &mqttUser, &mqttPasswd, mqttPort); EepromReadConfig(conf);
hostName = confHost; mode = conf.bootMode;
if (mode == BOOTMODE_NORMAL || mode == BOOTMODE_OTA) { if (mode == BOOTMODE_NORMAL || mode == BOOTMODE_OTA) {
SKETCH_DEBUG_PRINTLN("Configuration Found !:"); SKETCH_DEBUG_PRINTLN("Configuration Found !:");
SKETCH_DEBUG_PRINTLN(mode); SKETCH_DEBUG_PRINTLN(conf.bootMode);
SKETCH_DEBUG_PRINTLN(confSsid); SKETCH_DEBUG_PRINTLN(conf.ssid);
SKETCH_DEBUG_PRINTLN(confPassword); SKETCH_DEBUG_PRINTLN(conf.host);
SKETCH_DEBUG_PRINTLN(confHost); SKETCH_DEBUG_PRINTLN(conf.mqttServer);
SKETCH_DEBUG_PRINTLN(mqttServer); SKETCH_DEBUG_PRINTLN(conf.mqttUser);
SKETCH_DEBUG_PRINTLN(mqttUser); SKETCH_DEBUG_PRINTLN(conf.mqttPasswd);
SKETCH_DEBUG_PRINTLN(mqttPasswd); SKETCH_DEBUG_PRINTLN(conf.mqttPort);
SKETCH_DEBUG_PRINTLN(mqttPort);
SKETCH_DEBUG_PRINTLN(); SKETCH_DEBUG_PRINTLN();
} else { } else {
SKETCH_DEBUG_PRINTLN("No configuration saved"); SKETCH_DEBUG_PRINTLN("No configuration saved");
} }
SKETCH_DEBUG_PRINT("Force Setup Mode ? :"); SKETCH_DEBUG_PRINTF("Force Setup Mode ? : %s\n", txStatus ? "No" : "Yes");
SKETCH_DEBUG_PRINT(txStatus ? "No" : "Yes"); if (txStatus == 0) {
SKETCH_DEBUG_PRINTLN(); mode = BOOTMODE_SETUP;
}
WifiSetup(mode, txStatus == 0, confSsid, confPassword, confHost); WifiSetup(conf);
MqttSetup(mqttServer, mqttUser, mqttPasswd, mqttPort, confHost); if (mode == BOOTMODE_NORMAL) {
MqttSetup(conf.mqttServer, conf.mqttUser, conf.mqttPasswd, conf.mqttPort, conf.host);
MqttPublishIP(WiFi.localIP().toString());
}
if (mode == BOOTMODE_OTA) { if (mode == BOOTMODE_OTA) {
OTASetup(); OTASetup();
} else { } else {
if (BMP180Setup(SDA, SCL)) if (!BMP180Setup(CONFIG_BMP180_SDA, CONFIG_BMP180_SCL)) {
SKETCH_DEBUG_PRINTLN("BMP180 init success"); SKETCH_DEBUG_PRINTLN("BMP180 init success");
}
if (!BMP280Setup()) {
SKETCH_DEBUG_PRINTLN("BMP280 init success");
}
if (!DHTSetup(CONFIG_DHT_PIN)) {
SKETCH_DEBUG_PRINTLN("DHT init success");
}
if (!DrySetup(CONFIG_DRY_POWER_PIN)) {
SKETCH_DEBUG_PRINTLN("DRY init success");
}
if(!BME680Setup()){
SKETCH_DEBUG_PRINTLN("BME680 init success");
}
if(!BME680BSECSetup()){
SKETCH_DEBUG_PRINTLN("BME680 with BSEC init success");
}
if(!TeleinfoSetup()){
SKETCH_DEBUG_PRINTLN("Teleinfo init success");
}
if(!SCD4XSetup()){
SKETCH_DEBUG_PRINTLN("SCD4X init success");
}
WebSetupServer(mode); WebSetupServer(mode);
} }
samplingPeriod = conf.samplingPeriod;
#ifdef CONFIG_ENABLE_POWER_SAVE
wifi_set_sleep_type(LIGHT_SLEEP_T);
#endif
} }
uint nbCycle = 0;
void loop() { void loop() {
if (mode == BOOTMODE_OTA) { if (mode == BOOTMODE_OTA) {
ArduinoOTA.handle(); ArduinoOTA.handle();
} else { } else {
server.handleClient(); server.handleClient();
MqttCheckSubscription(); if (mode == BOOTMODE_NORMAL) {
delay(WEB_DELAY_MS); MqttCheckSubscription();
MqttCheckIRQ();
}
delay(CONFIG_WEB_DELAY_MS);
TeleinfoRetrieve(teleIinst, telePapp, teleBase);
nbCycle++; nbCycle++;
if (nbCycle > SAMPLING_PERIODE_MS / WEB_DELAY_MS) { if (nbCycle > samplingPeriod / CONFIG_WEB_DELAY_MS) {
if (BMP180IsConnected() && BMP180GetTempAndPressure(temp, pressure) == 0) { std::vector<struct mqttInfo> batchInfo;
SKETCH_DEBUG_PRINT("Current T°C "); if (!BMP180GetTempAndPressure(temp, pressure)) {
SKETCH_DEBUG_PRINT(temp); SKETCH_DEBUG_PRINTF("Current %f°C Pressure %fmB\n", temp, pressure);
SKETCH_DEBUG_PRINT( " Pressure mB "); batchInfo.push_back({(float)temp, TEMPERATURE_FEED_FORMAT, 0, 0});
SKETCH_DEBUG_PRINTLN(pressure); batchInfo.push_back({(float)pressure, PRESSURE_FEED_FORMAT, 0, 0});
MqttPublish(temp, pressure); }
} else { if (!BMP280GetTempAndPressure(temp, pressure)) {
SKETCH_DEBUG_PRINTLN("Cannot get T°C"); SKETCH_DEBUG_PRINTF("Current %f°C Pressure %fmB\n", temp, pressure);
batchInfo.push_back({(float)temp, TEMPERATURE_FEED_FORMAT, 0, 0});
batchInfo.push_back({(float)pressure, PRESSURE_FEED_FORMAT, 0, 0});
}
if (!DHTGetTempAndHumidity(dhtTemp, dhtHumidity)) {
SKETCH_DEBUG_PRINTF("Current %f°C %f%% Humidity\n", dhtTemp, dhtHumidity);
batchInfo.push_back({dhtTemp, TEMPERATURE_DHT_FEED_FORMAT, 0, 0});
batchInfo.push_back({dhtHumidity, HUMIDITY_DHT_FEED_FORMAT, 0, 0});
}
if (!SCD4XGetMeasure(SCD4xT, SCD4xH, SCD4xCo2)) {
SKETCH_DEBUG_PRINTF("Current %f°C %f Humidity, Current C02 %d\n", SCD4xT, SCD4xH, SCD4xCo2);
batchInfo.push_back({SCD4xT, SCD4X_TEMPERATURE_FEED_FORMAT, 0, 0});
batchInfo.push_back({SCD4xH, SCD4X_HUMIDITY_FEED_FORMAT, 0, 0});
batchInfo.push_back({(float)SCD4xCo2, SCD4X_CO2_FEED_FORMAT, 0, 0});
}
if (!DryGetMeasure(dryness)) {
SKETCH_DEBUG_PRINTF("Current dryness %d %%\n", (dryness * 100) / 1024);
batchInfo.push_back({(float)dryness, DRY_FEED_FORMAT, 0, 0});
}
if (!BME680GetMeasure(bme680T, bme680P, bme680H, bme680G, bme680A)) {
SKETCH_DEBUG_PRINT("Current T°C: ");
SKETCH_DEBUG_PRINT(bme680T);
SKETCH_DEBUG_PRINT(" Pressure hPa: ");
SKETCH_DEBUG_PRINT(bme680P);
SKETCH_DEBUG_PRINT(" Humidity %: ");
SKETCH_DEBUG_PRINTLN(bme680H);
SKETCH_DEBUG_PRINT(" Gaz kOhms: ");
SKETCH_DEBUG_PRINTLN(bme680G);
SKETCH_DEBUG_PRINT(" Altitude M: ");
SKETCH_DEBUG_PRINTLN(bme680A);
batchInfo.push_back({bme680T, BME680_TEMPERATURE_FEED_FORMAT, 0, 0});
batchInfo.push_back({bme680P, BME680_PRESSURE_FEED_FORMAT, 0, 0});
batchInfo.push_back({bme680H, BME680_HUMIDITY_FEED_FORMAT, 0, 0});
batchInfo.push_back({bme680G, BME680_GAZ_FEED_FORMAT, 0, 0});
batchInfo.push_back({bme680A, BME680_ALT_FEED_FORMAT, 0, 0});
} }
nbCycle = 0;
if (!BME680BSECGetMeasure(bme680BSECT, bme680BSECP, bme680BSECH, bme680BSECIaq,
bme680BSECIaqAcc)) {
SKETCH_DEBUG_PRINT("Current T°C: ");
SKETCH_DEBUG_PRINT(bme680BSECT);
SKETCH_DEBUG_PRINT(" Pressure hPa: ");
SKETCH_DEBUG_PRINT(bme680BSECP);
SKETCH_DEBUG_PRINT(" Humidity %: ");
SKETCH_DEBUG_PRINT(bme680BSECH);
SKETCH_DEBUG_PRINT(" Indoor Air Quality: ");
SKETCH_DEBUG_PRINT(bme680BSECIaq);
SKETCH_DEBUG_PRINT(" IAQ Accuracy: ");
SKETCH_DEBUG_PRINTLN(bme680BSECIaqAcc);
batchInfo.push_back({bme680BSECT, BME680_TEMPERATURE_FEED_FORMAT, 0, 0});
batchInfo.push_back({bme680BSECP, BME680_PRESSURE_FEED_FORMAT, 0, 0});
batchInfo.push_back({bme680BSECH, BME680_HUMIDITY_FEED_FORMAT, 0, 0});
batchInfo.push_back({bme680BSECIaq, BME680_IAQ_FEED_FORMAT, 0, 0});
batchInfo.push_back({bme680BSECIaqAcc, BME680_IAQ_ACC_FEED_FORMAT, 0, 0});
}
TeleinfoRetrieve(teleIinst, telePapp, teleBase, batchInfo);
if (mode == BOOTMODE_NORMAL)
if (MqttBatchPublish(batchInfo, conf.mqttUser, conf.host))
WifiSetup(conf);
nbCycle = 0;
} }
} }
} }

View File

@ -0,0 +1,87 @@
#pragma once
#include "config_device.h"
/* DO NOT CHANGE THIS FILE */
/* Contains values that SHOULD be defined to have the sketch working */
/* Modify value in config_device.h instead */
#ifndef CONFIG_WEB_DELAY_MS
#define CONFIG_WEB_DELAY_MS 100
#endif
#ifndef CONFIG_SAMPLING_PERIOD_MS
#define CONFIG_SAMPLING_PERIOD_MS 60000
#endif
#if defined(CONFIG_ENABLE_BME680) && defined(CONFIG_BME680_BSEC_ENABLE)
#error "BME680 and BME680 BSEC cannot be enabled together"
#endif
#ifndef CONFIG_BME680_BSEC_I2C_ADDR
#define CONFIG_BME680_BSEC_I2C_ADDR 0x76
#endif
#if defined(CONFIG_ENABLE_BMP180) && !defined(CONFIG_BMP180_SDA)
#error "When enabling BMP180, you should configure SDA pin"
#elif !defined(CONFIG_ENABLE_BMP180)
#define CONFIG_BMP180_SDA 0
#endif
#if defined(CONFIG_ENABLE_BMP180) && !defined(CONFIG_BMP180_SCL)
#error "When enabling BMP180, you should configure SLC pin"
#elif !defined(CONFIG_ENABLE_BMP180)
#define CONFIG_BMP180_SCL 0
#endif
#if defined(CONFIG_ENABLE_DHT) && !defined(CONFIG_DHT_PIN)
#error "When enabling DHT, you should configure SDA pin"
#elif !defined(CONFIG_ENABLE_DHT) && !defined(CONFIG_DHT_PIN)
#define CONFIG_DHT_PIN 0
#endif
#ifndef CONFIG_DRY_POWER_PIN
#define CONFIG_DRY_POWER_PIN -1
#endif
#ifndef CONFIG_SSID_NAME
#define CONFIG_SSID_NAME "ESPConfigurator"
#endif
#ifndef CONFIG_CONTROLLED_PWM
#define CONFIG_CONTROLLED_PWM {}
#endif
#ifndef CONFIG_OBSERVED_GPIO
#define CONFIG_OBSERVED_GPIO {}
#endif
#ifndef CONFIG_CONTROLLED_GPIO
#define CONFIG_CONTROLLED_GPIO {}
#endif
#ifndef CONFIG_EEPROM_SIZE
#define CONFIG_EEPROM_SIZE 256
#endif
#ifndef CONFIG_SETUP_GPIO
#define CONFIG_SETUP_GPIO 14
#endif
#ifndef CONFIG_DHT_TYPE
#define CONFIG_DHT_TYPE DHT11
#endif
#if CONFIG_SETUP_GPIO == 3 || CONFIG_SETUP_GPIO == 1
#define CONFIG_SERIAL_SHOULD_SWAP
#endif
#if defined(CONFIG_ENABLE_TELEINFO)
#warning "TELEINFO is using SERIAL for communication. Debug will be on Serial1 (D4)"
#define DEBUG_PRINTER_WIFICONTROLSENSOR Serial1
#if defined(CONFIG_SERIAL_SHOULD_SWAP)
#error "When enabling TELEINFO, SERIAL_SHOULD_SWAP cannot be enabled (SETUP_GPIO == 1 or 3)"
#endif
#if defined(CONFIG_ENABLE_EXTRA_GPIO)
#error "When enabling TELEINFO, ENABLE_EXTRA_CPIO cannot be enabled"
#endif
#endif

View File

@ -0,0 +1,80 @@
#pragma once
#include "pins_arduino.h"
// Enable Serial Console (Disable to save space and power)
#define CONFIG_SKETCH_DEBUG
// Switch Serial console on gpio 13 and 15 (So you can use GPIO 1 and 3 for other things)
//#define CONFIG_ENABLE_EXTRA_GPIO
// Disable SSL (so mqtts) to save some place (~52ko)
//#define CONFIG_DISABLE_SSL
//#define CONFIG_DISABLE_WEB
//#define CONFIF_DISABLE_OTA
//#define CONFIG_DISABLE_MQTT
// Enable the temperature, pressure, humidity and gaz Sensor BME680 on standard i2c esp8266 pins
// It use default i2c pin GPIO4(D2): SDA, GPIO5(D1):SCL
// Should be powered by 3.3v and sampled every 3sec or 300s (Or you should adapt bsec_config_iaq in BME680_BSEC.ino )
//#define CONFIG_BME680_BSEC_ENABLE
#define CONFIG_BME680_BSEC_I2C_ADDR 0x77
// Enable the temperature, pressure, humidity and gaz Sensor BME680 on standard i2c esp8266 pins
// It use default i2c pin GPIO4(D2): SDA, GPIO5(D1):SCL
//#define CONFIG_ENABLE_BME680
// Enable the temperatue and pressure Sensor BMP180
// (CONFIG_BMP180_SDA and CONFIG_BMP180_SDA should be defined as well)
//#define CONFIG_ENABLE_BMP180
//#define CONFIG_BMP180_SDA SDA //D2
//#define CONFIG_BMP180_SCL SCL //D1
//
//#define CONFIG_ENABLE_DHT
//#define CONFIG_DHT_PIN 2
//#define CONFIG_DHT_TYPE DHT22
//#define CONFIG_ENABLE_BMP280
//#define CONFIG_ENABLE_DRY_SENSOR
//If the dry sensor is powered by a GPIO, this GPIO could be defined here
//#define CONFIG_DRY_POWER_PIN 13
//Advised CONFIG_SAMPLING_PERIOD_MS is 5s for this sensor
//#define CONFIG_ENABLE_SCD4X
// Enable light sleep to save some power (http://bbs.espressif.com/viewtopic.php?f=6&t=133&p=485&hilit=sleep+modem#p485)
#define CONFIG_ENABLE_POWER_SAVE
// Disable mDNS can also save power
#define CONFIG_ENABLE_MDNS
// Long press on this button will put device in setup mode at runtime
#define CONFIG_SETUP_BUTTON 0
// Teleinfo https://github.com/hallard/LibTeleinfo/
#define CONFIG_ENABLE_TELEINFO
/* DEFAULT VALUE ALSO DEFINED IN CONFIG.H */
//If this GPIO is LOW at boot, device will enter setup mode
#define CONFIG_SETUP_GPIO 14 //D5
// Time to sleep between 2 webserver request (increase it reduce battery usage but increase latency)
#define CONFIG_WEB_DELAY_MS 800
// Get sensors value every X ms
#define CONFIG_SAMPLING_PERIOD_MS 30000
// Name of the SSID when in AP mode for configuration
#define CONFIG_SSID_NAME "ESPConfiguratorBureau"
// GPIO that can be set or get by mqtt and set via http
// Should have less value than MAXSUBSCRIPTIONS
//#define CONFIG_CONTROLLED_GPIO {12,13}
// GPIO that can be get by mqtt and http
// Pin 6 to 11 and 16 can not be used for mqtt
//#define CONFIG_OBSERVED_GPIO {5}
// GPIO used in PWM
//#define CONFIG_CONTROLLED_PWM {}
// EEPROM SIZE
// Max is 4096, but this amount will be allocated in RAM for reading its content
//#CONFIG_EEPROM_SIZE 256

View File

@ -1,14 +1,16 @@
#pragma once #pragma once
//#define SKETCH_DEBUG //#define CONFIG_SKETCH_DEBUG
// Set where debug messages will be printed. // Set where debug messages will be printed.
#define DEBUG_PRINTER Serial #ifndef DEBUG_PRINTER_WIFICONTROLSENSOR
#define DEBUG_PRINTER_WIFICONTROLSENSOR Serial
#endif
#ifdef SKETCH_DEBUG #ifdef CONFIG_SKETCH_DEBUG
#define SKETCH_DEBUG_INIT(speed){ DEBUG_PRINTER.begin(speed); } #define SKETCH_DEBUG_INIT(speed){ DEBUG_PRINTER_WIFICONTROLSENSOR.begin(speed); }
#define SKETCH_DEBUG_PRINT(...) { DEBUG_PRINTER.print(__VA_ARGS__); } #define SKETCH_DEBUG_PRINT(...) { DEBUG_PRINTER_WIFICONTROLSENSOR.print(__VA_ARGS__); }
#define SKETCH_DEBUG_PRINTF(...) { DEBUG_PRINTER.printf(__VA_ARGS__); } #define SKETCH_DEBUG_PRINTF(...) { DEBUG_PRINTER_WIFICONTROLSENSOR.printf(__VA_ARGS__); }
#define SKETCH_DEBUG_PRINTLN(...) { DEBUG_PRINTER.println(__VA_ARGS__); } #define SKETCH_DEBUG_PRINTLN(...) { DEBUG_PRINTER_WIFICONTROLSENSOR.println(__VA_ARGS__); }
#else #else
#define SKETCH_DEBUG_INIT(speed) #define SKETCH_DEBUG_INIT(speed)
#define SKETCH_DEBUG_PRINT(...) {} #define SKETCH_DEBUG_PRINT(...) {}

View File

@ -0,0 +1,9 @@
#pragma once
#ifdef CONFIG_ENABLE_DRY_SENSOR
int DrySetup(int powerGPIO);
int DryGetMeasure(int &dry);
#else
int DrySetup(int){return -1;}
int DryGetMeasure(int){return -1;}
#endif

View File

@ -0,0 +1,24 @@
#ifdef CONFIG_ENABLE_DRY_SENSOR
#include "dry_sensor.h"
int dryGPIO;
int DrySetup(int powerGPIO){
dryGPIO = powerGPIO;
if(dryGPIO >= 0){
pinMode(dryGPIO, OUTPUT);
}
return 0;
}
int DryGetMeasure(int &dry){
if(dryGPIO >= 0){
digitalWrite(dryGPIO,1);
delay(50);
}
dry = analogRead(A0);
if(dryGPIO >= 0){
digitalWrite(dryGPIO,0);
}
return 0;
}
#endif

View File

@ -0,0 +1,14 @@
#pragma once
#ifdef CONFIG_ENABLE_DHT
#include <DHT.h>
#define DHTTYPE CONFIG_DHT_TYPE
DHT *dht = NULL;
int DHTSetup(int pin);
int DHTGetTempAndHumidity(float &t, float &h);
bool DHTIsConnected();
#else //CONFIG_ENABLE_DHT
int DHTSetup(int){SKETCH_DEBUG_PRINTLN("DHT is disabled at build time"); return -1;};
int DHTGetTempAndHumidity(float &, float &){return -1;};
bool DHTIsConnected(){return false;};
#endif

View File

@ -0,0 +1,28 @@
#ifdef CONFIG_ENABLE_DHT
#include "sensor_DHT.h"
int DHTSetup(int pin){
dht = new DHT(pin, DHTTYPE);
dht->begin();
return 0;
}
int DHTGetTempAndHumidity(float &t, float &h){
if(!DHTIsConnected())
goto err;
t = dht->readTemperature();
h = dht->readHumidity();
if(isnan(t) || isnan(h))
goto err;
return 0;
err:
t=0;
h=0;
return -1;
}
bool DHTIsConnected(){
//No way to know if connected
//Check at least if initialized
return dht != NULL;
}
#endif

16
WifiControlSensor/utils.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#define NB_ELEMENTS(x) (sizeof(x)/ sizeof(x[0]))
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define findIndex(x,y) findIdx(x, y, NB_ELEMENTS((y)))
int findIdx(int el, const int array[], uint size){
for (uint i = 0; i < size; i++) {
if (el == array[i])
return i;
}
return -1;
}