Compare commits

..

1 Commits

Author SHA1 Message Date
Mathieu Maret cfe890e3c7 First in prod 2016-03-29 01:06:44 +02:00
31 changed files with 251 additions and 1784 deletions

View File

@ -1,25 +0,0 @@
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
View File

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

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

View File

@ -1,5 +1,3 @@
[![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.
@ -22,26 +20,10 @@ 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 get measure from several sensors: Provide previous WiFiAccessPointConfigurator features and can also measure temperature and pressure from a BMP180.
* BMP180 Those measure can be shared by MQTT. MQTT details (server, username, passwd, port) can be configured by a web page.
* 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, a fork of the Adafruit Mqtt library should be installed (gitlab@gitlab.mathux.org:Mathieu/adaAdafruit_MQTT_Libraryfruit_mqtt_library.git To use mqtt, the Adafruit Mqtt library should be installed.
-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

View File

@ -1,86 +0,0 @@
#!/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

@ -1,26 +0,0 @@
#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

@ -1,40 +0,0 @@
#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

@ -1,16 +0,0 @@
#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

@ -1,153 +0,0 @@
#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,18 +1,21 @@
#pragma once #pragma once
#ifdef CONFIG_ENABLE_BMP180 #ifdef 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 //CONFIG_ENABLE_BMP80 #else //ENABLE_BMP80
int BMP180GetTemperature(double &){return -1;}; int BMP180GetTemperature(double &t){return 0;};
int BMP180GetTempAndPressure(double &, double &){return -1;}; int BMP180GetTempAndPressure(double &t, double &p){return 0;};
int BMP180Setup(int , int ){SKETCH_DEBUG_PRINTLN("BMP180 is disabled at build time"); return -1;}; int BMP180Setup(int , int ){SKETCH_DEBUG_PRINTLN("BMP180 is disabled at build time"); return 0;};
bool BMP180IsConnected(){return false;}; bool BMP180IsConnected(){return 0;};
#endif #endif

View File

@ -1,16 +1,8 @@
#ifdef CONFIG_ENABLE_BMP180 #ifdef 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);
if (!bmp180Connected){ return bmp180Connected;
SKETCH_DEBUG_PRINTLN("Cannot connect to BMP180");
return -1;
}
return 0;
} }
bool BMP180IsConnected() { bool BMP180IsConnected() {
@ -19,8 +11,6 @@ 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

@ -1,15 +0,0 @@
#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

@ -1,44 +0,0 @@
#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

@ -1,28 +0,0 @@
#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,37 +1,21 @@
/* EEPROM LAYOUT /* EEPROM LAYOUT
"BOOTMODE;SSID;PASSWORD;HOSTNAME;MQTT_SERVER;MQTT_USERNAME;MQTT_PASSWD;MQTT_PORT;IP_CONFIG;IP;GATEWAY;NETMASK;DNS1;DNS2;WIFI_CHANNEL;WIFI_BSSID;" "BOOTMODE;SSID;PASSWORD;HOSTNAME;MQTT_SERVER;MQTT_USERNAME;MQTT_PASSWD;MQTT_PORT;"
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)
#if (CONFIG_EEPROM_SIZE + BSEC_MAX_STATE_BLOB_SIZE) >= SPI_FLASH_SEC_SIZE int EepromSaveConfig(uint8_t bootMode, String ssid, String password, String host, String mqttServer, String mqttUser, String mqttPasswd, int mqttPort) {
#error "CONFIG_EEPROM_SIZE too big"
#endif
char eeprom[CONFIG_EEPROM_SIZE];
int EepromSaveConfig(productConfig &config) {
String eeprom; String eeprom;
eeprom = String(config.bootMode) + ";" + config.ssid + ";" + config.password + ";" eeprom = String(bootMode) + ";" + ssid + ";" + password + ";" + host + ";" + mqttServer + ";" + mqttUser + ";" + mqttPasswd + ";" + String(mqttPort) + ";";
+ 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() > CONFIG_EEPROM_SIZE ) if (eeprom.length() > EEPROM_SIZE )
return -EMSGSIZE; return -EMSGSIZE;
SKETCH_DEBUG_PRINTLN("Saving " + eeprom); SKETCH_DEBUG_PRINTLN("Saving " + eeprom);
for (uint i = 0; i < eeprom.length() && i < CONFIG_EEPROM_SIZE; i++) { for (int i = 0; i < eeprom.length() && i < EEPROM_SIZE; i++) {
EEPROM.write(i, eeprom.charAt(i)); EEPROM.write(i, eeprom.charAt(i));
} }
@ -53,97 +37,37 @@ void readConfElement(char** element, int &i) {
do { do {
eeprom[i] = EEPROM.read(i); eeprom[i] = EEPROM.read(i);
i++; i++;
} while (i < CONFIG_EEPROM_SIZE && eeprom[i - 1] != ';'); } while (i < EEPROM_SIZE && eeprom[i - 1] != ';');
eeprom[i - 1] = '\0'; eeprom[i - 1] = '\0';
if (i >= CONFIG_EEPROM_SIZE){ if (i >= EEPROM_SIZE)
SKETCH_DEBUG_PRINTLN("Looks like there is a configuration issue (too long)");
**element = '\0'; **element = '\0';
}
} }
void EepromReadConfig(productConfig &config) { void EepromReadConfig(uint8_t &bootMode, char **ssid, char **password, char **host, char **mqttServer, char **mqttUser, char **mqttPasswd, int &mqttPort) {
int i = 2; int i = 2;
uint8_t boot = EEPROM.read(0); uint8_t boot = EEPROM.read(0);
char *tmpString; char *mqttPortString = "";
if (boot == '1') { if (boot == '1') {
config.bootMode = BOOTMODE_SETUP; bootMode = BOOTMODE_NORMAL;
} else if (boot == '2') { } else if (boot == '2') {
config.bootMode = BOOTMODE_NORMAL; bootMode = BOOTMODE_OTA;
} 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
config.bootMode = BOOTMODE_SETUP; bootMode = BOOTMODE_SETUP;
return; return;
} }
readConfElement(&config.ssid, i); readConfElement(ssid, i);
readConfElement(&config.password, i); readConfElement(password, i);
readConfElement(&config.host, i); readConfElement(host, i);
readConfElement(&config.mqttServer, i); readConfElement(mqttServer, i);
readConfElement(&config.mqttUser, i); readConfElement(mqttUser, i);
readConfElement(&config.mqttPasswd, i); readConfElement(mqttPasswd, i);
readConfElement(&tmpString, i); readConfElement(&mqttPortString, i);
config.mqttPort = atoi(tmpString); mqttPort = atoi(mqttPortString);
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;
}
} }

View File

@ -1,64 +0,0 @@
#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,108 +1,54 @@
#ifndef CONFIG_DISABLE_MQTT // Create an ESP8266 WiFiClient class to connect to the MQTT server.
#include <stdarg.h> WiFiClient client;
#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_ip; Adafruit_MQTT_Publish *mqtt_temp;
Adafruit_MQTT_Publish *mqttGpio[MAXSUBSCRIPTIONS] = {}; Adafruit_MQTT_Publish *mqtt_pressure;
Adafruit_MQTT_Publish *mqttPwm[MAXSUBSCRIPTIONS] = {};
Adafruit_MQTT_Publish *mqttGpioObserved[MAX_GPIO_OBSERVED] = {};
gpioInfo mqttIRQ[MAX_PIN + 1] = {};
#define FEED_MAX_SIZE 96 #define NB_ELEMENTS(x) (sizeof(x)/ sizeof(x[0]))
#define FEED_MAX_SIZE 64
bool isMqttConfigured = false; #define TEMPERATURE_FEED_FORMAT "/feeds/%s/temperature"
bool useMqtts = false; #define PRESSURE_FEED_FORMAT "/feeds/%s/pressure"
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};
int MqttSetup(const char *server, const char *user, const char *passwd, int port, const char *hostname) { #define GPIO_FEED_FORMAT "/feeds/%s/gpio/%d"
useMqtts = (port == 8883); #define GPIO_SET_FEED_FORMAT "/feeds/%s/gpio/%d/set"
isMqttConfigured = server[0] != '\0';
if (!isMqttConfigured) char *mqttId;
return 0; char GPIO_FEED[MAXSUBSCRIPTIONS][FEED_MAX_SIZE] = {};
char GPIO_SET_FEED[MAXSUBSCRIPTIONS][FEED_MAX_SIZE] = {};
#ifndef CONFIG_DISABLE_SSL Adafruit_MQTT_Publish * mqttGpio[MAXSUBSCRIPTIONS] = {};
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);
mqtt_ip = MqttCreatePublisher(0, 1, IP_FEED_FORMAT, user, hostname); int MqttSetup(char *server, char *user, char *passwd, int port, char * hostname) {
mqttId = hostname;
snprintf(temperatureFeed, FEED_MAX_SIZE, TEMPERATURE_FEED_FORMAT, mqttId);
snprintf(pressureFeed, FEED_MAX_SIZE, PRESSURE_FEED_FORMAT, mqttId);
if (NB_ELEMENTS(gpioControlled) + NB_ELEMENTS(pwmControlled) > MAXSUBSCRIPTIONS) { mqtt = new Adafruit_MQTT_Client(&client, server, port, user, passwd);
SKETCH_DEBUG_PRINTF("Too much gpio/pwm to control\n Nb gpio %d Nb pwm %d Max is %d", mqtt_temp = new Adafruit_MQTT_Publish(mqtt, temperatureFeed);
NB_ELEMENTS(gpioControlled), NB_ELEMENTS(pwmControlled), MAXSUBSCRIPTIONS); mqtt_pressure = new Adafruit_MQTT_Publish(mqtt, pressureFeed);
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 (uint i = 0 ; i < NB_ELEMENTS(gpioControlled); i++) { for (int i = 0 ; i < NB_ELEMENTS(gpioWatched) && i < MAXSUBSCRIPTIONS; i++) {
mqtt->subscribe(MqttCreateSubscribe(GPIO_SET_FEED_FORMAT, user, hostname, gpioControlled[i])); snprintf(GPIO_FEED[i], FEED_MAX_SIZE, GPIO_FEED_FORMAT, mqttId, gpioWatched[i]);
mqttGpio[i] = MqttCreatePublisher(0, 0, GPIO_FEED_FORMAT, user, hostname, gpioControlled[i]); snprintf(GPIO_SET_FEED[i], FEED_MAX_SIZE, GPIO_SET_FEED_FORMAT, mqttId, gpioWatched[i]);
}
for (uint i = 0 ; i < NB_ELEMENTS(gpioObserved) && i < MAX_GPIO_OBSERVED ; i++) { Adafruit_MQTT_Subscribe *gpioSet = new Adafruit_MQTT_Subscribe(mqtt, GPIO_SET_FEED[i]);
mqttGpioObserved[i] = MqttCreatePublisher(0, 0, GPIO_FEED_FORMAT, user, hostname, gpioObserved[i]); mqtt->subscribe(gpioSet);
new HIB(gpioObserved[i], HIGH, MqttNofityIRQ , MqttNofityIRQ, NULL );
}
for (uint i = 0 ; i < NB_ELEMENTS(pwmControlled); i++) { Adafruit_MQTT_Publish *gpio = new Adafruit_MQTT_Publish(mqtt, GPIO_FEED[i]);
mqtt->subscribe(MqttCreateSubscribe(PWM_SET_FEED_FORMAT, user, hostname, pwmControlled[i])); mqttGpio[i] = gpio;
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 (isMqttConfigured && (mode == BOOTMODE_NORMAL)) ? mqtt->connected() : 0; return mqtt->connected();
} }
// Function to connect and reconnect as necessary to the MQTT server. // Function to connect and reconnect as necessary to the MQTT server.
@ -110,9 +56,6 @@ 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;
@ -132,23 +75,20 @@ int MqttConnect() {
return 0; return 0;
} }
template<typename T> int MqttPublish(Adafruit_MQTT_Publish *publisher, T value) { int MqttPublish(double temp, double pressure) {
if (MqttConnect() == 0) { if (MqttConnect() == 0) {
publisher->publish(value); SKETCH_DEBUG_PRINTLN("publishing !");
return 0; mqtt_temp->publish(temp);
mqtt_pressure->publish(pressure);
} }
return -1; return 0;
} }
int MqttPublishIP(const String &ip) { int getGpioFromSubscription(Adafruit_MQTT_Subscribe *subscription) {
return MqttPublish(mqtt_ip, ip.c_str()); char *temp = strstr(subscription->topic, "/gpio/");
}
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(pattern)); String gpioStr(temp + strlen("/gpio/"));
int idx = gpioStr.indexOf("/"); int idx = gpioStr.indexOf("/");
int gpio = gpioStr.substring(0, idx).toInt(); int gpio = gpioStr.substring(0, idx).toInt();
@ -158,68 +98,36 @@ int getGpioFromSubscription(Adafruit_MQTT_Subscribe *subscription, const char *p
return -1; return -1;
} }
void MqttNofityIRQ(uint8_t gpio, int value) { int getGpioWatchedIndex(int gpio) {
mqttIRQ[gpio].updated = 1; for ( int i = 0; i < NB_ELEMENTS(gpioWatched); i++) {
mqttIRQ[gpio].value = value; if (gpio == gpioWatched[i])
} 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);
MqttNofity(gpio, value); int watchIdx = getGpioWatchedIndex(gpio);
} if (watchIdx >= 0 ) {
mqttGpio[watchIdx]->publish(value);
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() 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, "/gpio/"); int gpio = getGpioFromSubscription(subscription);
if (gpio > 0 && findIndex(gpio, gpioControlled) >= 0) { SKETCH_DEBUG_PRINT("Got Subscription for gpio ");
SKETCH_DEBUG_PRINTF("Got Subscription for GPIO %d\n", gpio); SKETCH_DEBUG_PRINTLN(gpio);
char *value = (char *)subscription->lastread; if (gpio > 0 && getGpioWatchedIndex(gpio) >= 0) {
SKETCH_DEBUG_PRINTF("Receive data: %s\n", value); char *value = (char *) subscription->lastread;
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

View File

@ -1,23 +0,0 @@
#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

@ -1,61 +0,0 @@
#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

@ -1,23 +0,0 @@
#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

@ -1,77 +0,0 @@
#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,143 +1,54 @@
#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(CONFIG_SAMPLING_PERIOD_MS / 1000) + "\" ></head>" "<head><meta http-equiv=\"refresh\" content=\"" + String(SAMPLING_PERIODE_MS / 1000) + "\" ></head>"
"<h1>You are connected to " + String(conf.host) + "</h1>" "<h1>You are connected to " + String(hostName) + "</h1>"
"<fieldset>" "<fieldset>"
"<legend>Sensors</legend>" "<legend>Sensors</legend>"
#if defined CONFIG_ENABLE_BMP180 || defined CONFIG_ENABLE_BMP280 "Temperature " + String(temp, 2) + "C<br/>"
"" + ((BMP180IsConnected() || BMP280IsConnected()) ? "<h6>BMP180/280</h6>Temperature " + String(temp, 2) + "C<br/> Pressure " + String(pressure, 2) + "hPa<br/>" : "BMP180/280 Disconnected" ) + "" "Pressure " + String(pressure, 2) + "mB<br/>"
#endif "</fieldset>"
#ifdef CONFIG_ENABLE_DHT "<fieldset>"
"" + (DHTIsConnected() ? "<h6>DHT</h6>Temperature " + String(dhtTemp, 0) + "C<br/> Humidity " + String(dhtHumidity, 0) + "%<br/>" : "DHT Disconnected" ) + "" "<legend>Pump</legend>"
#endif "<a href=\"/gpio?gpio=13&amp;value=1\">Power PUMP ON</a><br/>"
#ifdef CONFIG_ENABLE_SCD4X "<a href=\"/gpio?gpio=13&value=0\">Power PUMP OFF</a><br/>"
"" + (SCD4XIsConnected() ? "<h6>SCD4X</h6>Temperature " + String(SCD4xT, 0) + "C<br/> Humidity " + String(SCD4xH, 0) + "%<br/> CO2 " + String(SCD4xCo2) + "ppm<br/>" : "SCD4X Disconnected" ) + "" "</fieldset>"
#endif "<fieldset>"
#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=\"/upload\">Update firmware</a><br/>" + optimiseConfig + "<a href=\"/otamode\">Put device in OTA mode</a><br/>"
"MQTT Status: " + (MqttIsConnected() ? "Connected" : "Disconnected") + "<br/>" "MQTT Status: " + (MqttIsConnected() ? "Connected" : "Disconnected") + "<br/>"
"Wifi Strength: " + WiFi.RSSI() + "dBm<br/>" "BMP 180 (Temp+Pression) Status: " + (BMP180IsConnected() ? "Connected" : "Disconnected") + "<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 WebSendError(const char *error) {
server.send(500, "text/plain", error);
}
void WebBuildSSIDList(String &datalist) {
int n = WiFi.scanNetworks();
datalist = "<datalist id=\"scan_ssid\">";
// sort by RSSI
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() { void WebHandleSetup() {
String ssidlist; uint8_t mode;
WebBuildSSIDList(ssidlist); char *confSsid = "";
String dhcpChecked = conf.ip_mode == 0 ? "checked" : ""; char *confPassword = "";
String staticChecked = conf.ip_mode == 1 ? "checked" : ""; char *confHost = "";
char *mqttServer = "";
char *mqttUser = "";
char *mqttPasswd = "";
int mqttPort = 1883;
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 list=\"scan_ssid\" type=\"text\" name=\"ssid\" value=\"" + String(conf.ssid) + "\" /></div>" "<div><label for=\"ssid\">Wifi SSID :</label> <br/><input type=\"text\" name=\"ssid\" value=\"" + String(confSsid) + "\" /></div>"
"" + ssidlist + "" "<div><label for=\"password\">Wifi Password :</label><br/><input type=\"password\" name=\"password\" /> </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(confHost) + "\" /> </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(conf.mqttServer) + "\" /> </div>" "<div><label for=\"mqttServer\">Server :</label><br/><input type=\"text\" name=\"mqttServer\" value=\"" + String(mqttServer) + "\" /> </div>"
"<div><label for=\"mqttUser\">Username :</label><br/><input type=\"text\" name=\"mqttUser\" value=\"" + String(conf.mqttUser) + "\" /> </div>" "<div><label for=\"mqttUser\">Username :</label><br/><input type=\"text\" name=\"mqttUser\" value=\"" + String(mqttUser) + "\" /> </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=\"mqttPasswd\">Password :</label><br/><input type=\"password\" name=\"mqttPasswd\" /> </div>"
"<div><label for=\"mqttPort\">Port :</label><br/><input type=\"text\" name=\"mqttPort\" value=\"" + String(conf.mqttPort) + "\" /> (8883 for secure Mqtts) </div>" "<div><label for=\"mqttPort\">Port :</label><br/><input type=\"text\" name=\"mqttPort\" value=\"" + String(mqttPort) + "\" /> </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>");
@ -153,90 +64,34 @@ 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 WebHandlePWM() {
if (!server.hasArg("gpio") || !server.hasArg("value")) {
server.send(500, "text/plain", "Bad arguments\r\n");
return;
}
MqttChangePWMValue(server.arg("gpio").toInt(), server.arg("value").toInt());
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() { void WebHandleSave() {
IPAddress ip; String password;
IPAddress gw; String ssid;
IPAddress mask; String hostName;
IPAddress dns; String mqttServer;
IPAddress dns2; String mqttUser;
String mqttPasswd;
if (!server.hasArg("ssid") || !server.hasArg("password") || !server.hasArg("host") if (!server.hasArg("ssid") || !server.hasArg("password") || !server.hasArg("host") || !server.hasArg("mqttServer") || !server.hasArg("mqttUser") || !server.hasArg("mqttPasswd") || !server.hasArg("mqttPort") ) {
|| !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"); 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) {
//Check Ip configuration server.send(500, "text/plain", "Cannot Save Credentials (Too long ?Contains \";\"?)\r\n");
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; return;
} }
samplingPeriod = newConf.samplingPeriod;
if (WiFi.softAPIP() != IPAddress((uint32_t)0)) { server.send(200, "text/html", "<h1>Configuration Saved</h1><br/>"
//In STA mode, we can test the AP connection "<a href=\"/reboot\">Reboot</a><br/>");
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("Activating OTA mode"); SKETCH_DEBUG_PRINTLN("Boot mode Set to OTA");
server.send(200, "text/html", "<h1>Setting OTA mode</h1><br/>" EepromSaveBootMode(BOOTMODE_OTA);
"Web ui will be disabled<br/>"); server.send(200, "text/html", "<h1>OTA Mode set</h1><br/>"
mode = BOOTMODE_OTA; "You can reboot now"
OTASetup(); "<a href=\"/reboot\">Reboot</a><br/>");
} }
void WebHandleNotFound() { void WebHandleNotFound() {
@ -260,99 +115,17 @@ void WebHandleReboot() {
ESP.restart(); ESP.restart();
} }
String statusToString(wl_status_t status) { void WebSetupServer(int bootmode) {
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,34 +1,17 @@
/* --------------------- 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 and a mqtt server */ /* Wifi passwd, and a mDNS hostname */
/* 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 to save some place for the sketch to upload */ /* "Flash Size" Menu. Use espota.py to upload OTA */
/* 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>
@ -36,55 +19,38 @@
#include <EEPROM.h> #include <EEPROM.h>
#include <ArduinoOTA.h> #include <ArduinoOTA.h>
#include <errno.h> #include <errno.h>
#include <HIB.h>
#include "config.h" #define ENABLE_BMP180
#include "utils.h" //#define SKETCH_DEBUG
#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"
extern "C" { //#define ENABLE_EXTRA_GPIO
#include <user_interface.h>
}
#define EEPROM_SIZE 256
char eeprom[EEPROM_SIZE];
#define BOOTMODE_SETUP 1 #define WEB_DELAY_MS 100
#define BOOTMODE_NORMAL 2 #define SAMPLING_PERIODE_MS 60000
#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;
int reconfig = 0; char *hostName = "";
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 = CONFIG_SSID_NAME; const char *ssid = "ESPConfigurator";
ESP8266WebServer server(80); ESP8266WebServer server(80);
@ -97,77 +63,43 @@ 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);
#ifdef CONFIG_SETUP_BUTTON /* MQTT decl */
void onLongButtonPressed(uint8_t pin) { int MqttConnect();
if (pin == CONFIG_SETUP_BUTTON) { int MqttIsConnected();
reconfig = 1; int MqttSetup(char *server, char *user, char *passwd, int port, char * hostname);
SKETCH_DEBUG_PRINTLN("Putting device in setup mode"); int MqttPublish(double temp, double pressure);
mode = BOOTMODE_SETUP; void MqttCheckSubscription();
WiFi.disconnect(); void MqttChangeGpioValue(int gpio, int value);
WiFi.softAP(ssid);
}
}
#endif
void WifiSetup(productConfig conf) { void WifiSetup(int bootmode, int forceSetup, char *confSsid, char *confPassword, char *confHost) {
IPAddress myIP; IPAddress myIP;
int connectionTry = 0; if (bootmode == BOOTMODE_SETUP || forceSetup) {
if (mode == BOOTMODE_SETUP) { SKETCH_DEBUG_PRINTLN("Configuring access point...");
SKETCH_DEBUG_PRINTLN("Configuring access point: " CONFIG_SSID_NAME);
/* You can set a password to the AP here */ /* You can set a password to the AP here */
WiFi.softAP(CONFIG_SSID_NAME); WiFi.softAP(ssid);
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...");
if (conf.ip_mode == 1) { WiFi.begin(confSsid, confPassword);
SKETCH_DEBUG_PRINTLN("Use static ip configuration");
WiFi.config(IPAddress(conf.ip), IPAddress(conf.gw), IPAddress(conf.mask), IPAddress(conf.dns), IPAddress(conf.dns2));
}
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_PRINTF("Using channel %u (0==auto)\n", conf.channel );
WiFi.begin(conf.ssid, conf.password, conf.channel, bssidConf);
while (WiFi.status() != WL_CONNECTED) { while (WiFi.status() != WL_CONNECTED) {
delay(50); delay(500);
SKETCH_DEBUG_PRINT("."); 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_PRINTF("\nWiFi connected\n"); SKETCH_DEBUG_PRINTLN("");
SKETCH_DEBUG_PRINTLN("WiFi connected");
#ifdef CONFIG_ENABLE_MDNS if (!MDNS.begin(confHost)) {
if (!MDNS.begin(conf.host)) {
SKETCH_DEBUG_PRINTLN("Error setting up MDNS responder!"); SKETCH_DEBUG_PRINTLN("Error setting up MDNS responder!");
} else { while (1) {
SKETCH_DEBUG_PRINTLN("mDNS responder started"); delay(1000);
#ifndef CONFIG_DISABLE_WEB }
//Needed for OTA by HTTP
MDNS.addService("http", "tcp", 80);
#endif
} }
#endif SKETCH_DEBUG_PRINTLN("mDNS responder started");
myIP = WiFi.localIP(); myIP = WiFi.localIP();
} }
@ -176,7 +108,6 @@ void WifiSetup(productConfig conf) {
} }
void OTASetup() { void OTASetup() {
#ifndef CONFIF_DISABLE_OTA
// Port defaults to 8266 // Port defaults to 8266
// ArduinoOTA.setPort(8266); // ArduinoOTA.setPort(8266);
@ -186,214 +117,115 @@ 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%%\n", (progress / (total / 100))); SKETCH_DEBUG_PRINTF("Progress: %u%%\r", (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) { if (error == OTA_AUTH_ERROR){ SKETCH_DEBUG_PRINTLN("Auth Failed");}
SKETCH_DEBUG_PRINTLN("Auth Failed"); else if (error == OTA_BEGIN_ERROR){ SKETCH_DEBUG_PRINTLN("Begin Failed");}
} else if (error == OTA_CONNECT_ERROR){ SKETCH_DEBUG_PRINTLN("Connect Failed");}
else if (error == OTA_BEGIN_ERROR) { else if (error == OTA_RECEIVE_ERROR){ SKETCH_DEBUG_PRINTLN("Receive Failed");}
SKETCH_DEBUG_PRINTLN("Begin Failed"); else if (error == OTA_END_ERROR){ SKETCH_DEBUG_PRINTLN("End 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_PRINTF("IP address: "); SKETCH_DEBUG_PRINT("IP address: ");
SKETCH_DEBUG_PRINTLN(WiFi.localIP()); SKETCH_DEBUG_PRINTLN(WiFi.localIP());
SKETCH_DEBUG_PRINTF("Free Space: %d\n", ESP.getFreeSketchSpace()); SKETCH_DEBUG_PRINT("Free Space: ");
#endif SKETCH_DEBUG_PRINTLN(ESP.getFreeSketchSpace());
} }
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
#if CONFIG_SERIAL_SHOULD_SWAP Serial.swap(); //Switch Serial on GPIO 13 & 15
SKETCH_DEBUG_PRINTLN("SWAP UART"); pinMode(3, INPUT_PULLUP);
Serial.swap(); // Switch Serial on GPIO 13 & 15 int txStatus = digitalRead(3);
#endif #ifndef ENABLE_EXTRA_GPIO
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(CONFIG_EEPROM_SIZE); EEPROM.begin(EEPROM_SIZE);
EepromReadConfig(conf); EepromReadConfig(mode, &confSsid, &confPassword, &confHost, &mqttServer, &mqttUser, &mqttPasswd, mqttPort);
mode = conf.bootMode; hostName = confHost;
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(conf.bootMode); SKETCH_DEBUG_PRINTLN(mode);
SKETCH_DEBUG_PRINTLN(conf.ssid); SKETCH_DEBUG_PRINTLN(confSsid);
SKETCH_DEBUG_PRINTLN(conf.host); SKETCH_DEBUG_PRINTLN(confPassword);
SKETCH_DEBUG_PRINTLN(conf.mqttServer); SKETCH_DEBUG_PRINTLN(confHost);
SKETCH_DEBUG_PRINTLN(conf.mqttUser); SKETCH_DEBUG_PRINTLN(mqttServer);
SKETCH_DEBUG_PRINTLN(conf.mqttPasswd); SKETCH_DEBUG_PRINTLN(mqttUser);
SKETCH_DEBUG_PRINTLN(conf.mqttPort); SKETCH_DEBUG_PRINTLN(mqttPasswd);
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_PRINTF("Force Setup Mode ? : %s\n", txStatus ? "No" : "Yes"); SKETCH_DEBUG_PRINT("Force Setup Mode ? :");
if (txStatus == 0) { SKETCH_DEBUG_PRINT(txStatus ? "No" : "Yes");
mode = BOOTMODE_SETUP; SKETCH_DEBUG_PRINTLN();
}
WifiSetup(conf); WifiSetup(mode, txStatus == 0, confSsid, confPassword, confHost);
if (mode == BOOTMODE_NORMAL) { MqttSetup(mqttServer, mqttUser, mqttPasswd, mqttPort, confHost);
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(CONFIG_BMP180_SDA, CONFIG_BMP180_SCL)) { if (BMP180Setup(SDA, 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();
if (mode == BOOTMODE_NORMAL) { MqttCheckSubscription();
MqttCheckSubscription(); delay(WEB_DELAY_MS);
MqttCheckIRQ();
}
delay(CONFIG_WEB_DELAY_MS);
TeleinfoRetrieve(teleIinst, telePapp, teleBase);
nbCycle++; nbCycle++;
if (nbCycle > samplingPeriod / CONFIG_WEB_DELAY_MS) { if (nbCycle > SAMPLING_PERIODE_MS / WEB_DELAY_MS) {
std::vector<struct mqttInfo> batchInfo; if (BMP180IsConnected() && BMP180GetTempAndPressure(temp, pressure) == 0) {
if (!BMP180GetTempAndPressure(temp, pressure)) { SKETCH_DEBUG_PRINT("Current T°C ");
SKETCH_DEBUG_PRINTF("Current %f°C Pressure %fmB\n", temp, pressure); SKETCH_DEBUG_PRINT(temp);
batchInfo.push_back({(float)temp, TEMPERATURE_FEED_FORMAT, 0, 0}); SKETCH_DEBUG_PRINT( " Pressure mB ");
batchInfo.push_back({(float)pressure, PRESSURE_FEED_FORMAT, 0, 0}); SKETCH_DEBUG_PRINTLN(pressure);
MqttPublish(temp, pressure);
} else {
SKETCH_DEBUG_PRINTLN("Cannot get T°C");
} }
if (!BMP280GetTempAndPressure(temp, pressure)) {
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});
}
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; nbCycle = 0;
} }
} }
} }

View File

@ -1,87 +0,0 @@
#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

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

@ -1,9 +0,0 @@
#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

@ -1,24 +0,0 @@
#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

@ -1,14 +0,0 @@
#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

@ -1,28 +0,0 @@
#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

View File

@ -1,16 +0,0 @@
#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;
}