first commit

This commit is contained in:
Jérôme Delacotte
2025-03-06 11:15:32 +01:00
commit 7b30d6e298
5276 changed files with 2108927 additions and 0 deletions

View File

@@ -0,0 +1,280 @@
#include "Domoticz.h"
Domoticz::Domoticz(String domoticz, String port, const char* ssid, const char* pass)
{
_domoticz = domoticz;
_port = port;
_ssid = ssid;
_pass = pass;
// // Domo
// _domoc[_domoticz.length() + 1];
// _domoticz.toCharArray(_domoc, _domoticz.length() + 1);
//
// // Port
// char portc[_port.length() + 1];
// _port.toCharArray(portc, _port.length() + 1);
// _iport = atoi(portc);
}
boolean Domoticz::connect()
{
// Domo
char _domoc[_domoticz.length() + 1];
_domoticz.toCharArray(_domoc, _domoticz.length() + 1);
// Port
char portc[_port.length() + 1];
_port.toCharArray(portc, _port.length() + 1);
int _iport = atoi(portc);
boolean connected = _client.connect(_domoc, _iport);
Serial.print(_domoc);
Serial.print(" ");
Serial.print(_iport);
Serial.print(" ");
Serial.print(" connected ");
Serial.print(connected);
Serial.print(" ");
Serial.println(WiFi.localIP());
return connected;
}
void Domoticz::close()
{
}
void Domoticz::initWifi()
{
WiFi.mode(WIFI_AP);
WiFi.begin(_ssid, _pass); //Connect to local Wifi
Serial.println();
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(500);
}
Serial.println("WiFi Connected!");
Serial.print("Connexion au reseau ");
Serial.println(WiFi.localIP());
}
String Domoticz::generateKey()
{
// WiFi.mode(WIFI_AP);
// Do a little work to get a unique-ish name. Append the
// last two bytes of the MAC (HEX'd) to "Thing-":
uint8_t mac[WL_MAC_ADDR_LENGTH];
WiFi.softAPmacAddress(mac);
String macID = String(mac[WL_MAC_ADDR_LENGTH - 2], HEX) + String(mac[WL_MAC_ADDR_LENGTH - 1], HEX);
macID.toUpperCase();
String AP_NameString = "ESP8266 Thing " + macID;
char AP_NameChar[AP_NameString.length() + 1];
memset(AP_NameChar, 0, AP_NameString.length() + 1);
for (int i = 0; i < AP_NameString.length(); i++)
{
AP_NameChar[i] = AP_NameString.charAt(i);
}
// WiFi.softAP(AP_NameChar, WiFiAPPSK);
Serial.println("macID=" + macID);
_macID = macID;
return macID;
}
void Domoticz::executeJson(String json, String svalue, String nvalue)
{
// Domo
char _domoc[_domoticz.length() + 1];
_domoticz.toCharArray(_domoc, _domoticz.length() + 1);
// Port
char portc[_port.length() + 1];
_port.toCharArray(portc, _port.length() + 1);
int _iport = atoi(portc);
_client.print("GET " + json); //"GET /json.htm?type=command&param=getuservariables");
if (svalue != "") {
_client.print("&svalue=" + svalue);
}
if (nvalue != "") {
_client.print("&nvalue=" + nvalue);
}
_client.println(" HTTP/1.1");
_client.print("Host: ");
_client.print(_domoc);
_client.print(":");
_client.println(_iport);
_client.println("User-Agent: Arduino-ethernet");
_client.println("Connection: close");
_client.println();
Serial.println("json=" + json);
}
//--------------------------------------------------------------------------------------------------
// Read current supply voltage
//--------------------------------------------------------------------------------------------------
String Domoticz::readVcc() {
// most exact output
uint16_t v = ESP.getVcc();
float_t v_cal = ((float) v / 1024.0f);
char v_str[10];
dtostrf(v_cal, 5, 3, v_str);
sprintf(v_str, "%s", v_str);
Serial.print("Tension lue ");
Serial.println(String(v_str));
return String(v_str); //ESP.getVcc() / 1024.0f; // Vcc in millivolts
}
String Domoticz::getIndexOfString(String data, String separator, int index)
{
int found = 0;
int strIndex[] = { 0, -1 };
int maxIndex = data.length() - 1;
for (int i = 0; i <= maxIndex && found <= index; i++) {
if (data.charAt(i) == separator.charAt(0) || i == maxIndex) {
found++;
strIndex[0] = strIndex[1] + 1;
strIndex[1] = (i == maxIndex) ? i + 1 : i;
}
}
return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
}
String Domoticz::readLine()
{
return _client.readStringUntil('\n');
}
void Domoticz::readTempDayValues(String idx)
{
String json = "/json.htm?type=graph&sensor=temp&idx=" + idx + "&range=day";
int nb = 0;
int nbVal = 0;
data = "";
labels = "";
String label = "";
Serial.println("readTempDayValues " + idx);
connect();
executeJson(json, "", "");
while (1)
{
// Avoid WDT reset during long process
yield();
String line = readLine();
if (line == "") {
break;
}
if (line.indexOf("\"d\"") != -1) {
//Serial.println(line + " ");
label = line.substring(line.indexOf(":") + 2, line.length());
}
if (line.indexOf("\"te\"") != -1) {
// Serial.println(line + " ");
nbVal++;
if (nbVal % 10) {
String val = line.substring(line.indexOf(":") + 2, line.indexOf(".") + 2);
if (val != NULL) {
//Serial.println(val);
if (data == "") {
data += val;
labels = "\"0\"";
} else {
char charBuf[50];
// val.toCharArray(charBuf, 50);
data += "," + val; //printf("%2.1f", atof(charBuf));
// data += "," + val;
// Serial.println(printf("%2.1f", atof(charBuf)));
labels = labels + label;
}
if (data.length() > 500) {
data = data.substring(data.indexOf(",") + 1);
labels = labels.substring(labels.indexOf(",") + 1);
}
yield();
}
}
}
nb++;
}
// Avoid WDT reset during long process
yield();
// Serial.println(data);
// Serial.println(labels);
yield();
Serial.print("Nombre de lignes ");
Serial.println(nb);
close();
}
void Domoticz::getIdFromDomoticz(String macID, Params * params)
{
String separator = ",";
int nb = 0;
Serial.println("Dans getIdFromDomoticz " + macID);
// -------------------
// LECTURE PARAM
// -------------------
if (params->esp8266_id == "") {
boolean connected = connect();
if (connected) {
Serial.println("Connected to domoticz");
executeJson("/json.htm?type=command&param=getuservariables", "", "");
// Read the first line of the request
while (1) {
String req = readLine();
if (req.indexOf(macID) != -1) {
Serial.println(req);
req = readLine();
req = readLine();
String val = req.substring(req.indexOf(":") + 2, req.length() - 1);
Serial.println(val);
val.replace("\"", "");
params->esp8266_id = getIndexOfString(val, separator, 0);
String tmp = getIndexOfString(val, separator, 1);
char tmpc[tmp.length() + 1];
tmp.toCharArray(tmpc, tmp.length() + 1);
params->sleepTime = atoi(tmpc);
if (params->sleepTime <= 0) {
params->sleepTime = 60;
}
params->esp8266_id_Vcc = getIndexOfString(val, separator, 2);
Serial.println("esp8266_id=" + params->esp8266_id);
Serial.println("sleepTime=" + tmp);
Serial.println("esp8266_id_Vcc=" + params->esp8266_id_Vcc);
break;
}
if (req == "" || nb > 500) {
break;
}
nb++;
}
_client.stop();
delay(100);
}
}
}

View File

@@ -0,0 +1,38 @@
#ifndef Domoticz_h
#define Domoticz_h
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include "Params.h"
class Domoticz
{
public:
Domoticz(String domoticz, String port, const char* ssid, const char* pass);
boolean connect();
void close();
void initWifi();
void executeJson(String json, String svalue, String nvalue);
//String getIdFromDomoticz();
String generateKey();
String readLine();
String readVcc();
void readTempDayValues(String idx);
void getIdFromDomoticz(String macID, Params * params);
static String getIndexOfString(String data, String separator, int index);
private:
public:
const char* _pass;
const char* _ssid;
WiFiClient _client;
char _domoc[];
int _iport;
String _domoticz;
String _port;
String _macID;
String data = "";
String labels = "";
};
#endif

View File

@@ -0,0 +1,142 @@
//extern "C" {
//#include "user_interface.h"
//}
// Need for getVcc
ADC_MODE(ADC_VCC);
/////////////////////
// Domoticz Classe
/////////////////////
#include "Domoticz.h"
Domoticz domo("192.168.1.3", "81", "Livebox-37cc", "8A6060920A8A86896F770F2C47");
#include "Modules.h"
Modules modules;
Params * params;
#include "ServeurWeb.h"
ServeurWeb * serveurWeb;
WiFiServer server(80);
#include "Octoprint.h"
Octoprint octoprint("192.168.1.3", "5000", "B5746ACFF37140D0B5F6FEAAC4413B5C");
#include "Somfy.h"
Somfy *somfy;
// Ticker mqtt_error_timer(somfy.blink_function, 10, 11);
// Ticker blink_timer(somfy.blink_function, 200, 21);
// Ticker publish_timer(somfy.blink_function, 10, 11);
// Convert image to char array http://www.digole.com/tools/PicturetoC_Hex_converter.php
Params p;
ServeurWeb sw;
Somfy s;
// domoticz
String macID = "";
unsigned long milli;
void setup()
{
Serial.begin(9600);
// /* sda scl */
// Wire.pins(SDA, SCL);
// Wire.begin(SDA, SCL);
// Conversion d'objet en pointeur
somfy = &s;
params = &p;
somfy->init();
serveurWeb = &sw;
serveurWeb->domoticz = &domo;
serveurWeb->modules = &modules;
serveurWeb->server = &server;
serveurWeb->server->begin();
delay(100);
domo.initWifi();
macID = domo.generateKey();
domo.getIdFromDomoticz(macID, params);
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, HIGH);
// octoprint.connect();
// octoprint.executeJson("/api/printer", "", "");
// octoprint.executeJsonPost("/api/printer/command", "{\"command\": \"M503\"}");
milli = 0; millis();
delay(100);
}
void loop()
{
//serveurWeb->loop();
somfy->loop();
// yield();
// files->ftpSrv.handleFTP(); //make sure in loop you call handleFTP()!!
// yield();
// if (milli == 0 || milli + params->sleepTime * 1000 <= millis() ) {
// // // Avoid WDT reset during long process
// // yield();
// milli = millis();
// modules.readTemp();
// printInfo();
//
// // Test Json
// domo.readTempDayValues(params->esp8266_id);
// }
}
void printInfo()
{
boolean connected = domo.connect();
Serial.println("Dans printInfo " + connected + ' ' + params->esp8266_id);
yield();
// Domoticz format /json.htm?type=command&param=udevice&idx=IDX&nvalue=0&svalue=TEMP;HUM;HUM_STAT
if (connected && params->esp8266_id != "") {
Serial.println("Dans set temperature" + String(modules.temp));
//domo.executeJson();
if (modules.temp < 50 && modules.temp > 0) {
String svalue = String(modules.temp) + ";" + String(modules.humidity) + ";0";
Serial.println(svalue);
domo.executeJson("/json.htm?type=command&param=udevice&idx=" + params->esp8266_id, svalue, "0");
yield();
domo._client.stop();
yield();
}
delay(200);
}
connected = domo.connect();
if (connected && params->esp8266_id_Vcc != "") {
Serial.print(" Envoi tension ");
Serial.print(params->esp8266_id_Vcc);
Serial.print(" ");
yield();
String vcc = domo.readVcc();
Serial.println(vcc);
yield();
// domo._client.print("GET /json.htm?type=command&param=udevice&idx=");
domo.executeJson("/json.htm?type=command&param=udevice&idx=" + params->esp8266_id_Vcc, vcc, "0");
domo._client.stop();
yield();
}
}

View File

@@ -0,0 +1,60 @@
#include "Modules.h"
// int status = WL_IDLE_STATUS; // the Wifi radio's status
//WiFiClient client;
// Dallas
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);
Modules::Modules()
{
Serial.println("--------------------------------------");
Serial.println("Init Module");
pinMode(RELAY_PIN, OUTPUT);
pinMode(RELAY_PIN_02, OUTPUT);
pinMode(RELAY_PIN_03, OUTPUT);
pinMode(RELAY_PIN_04, OUTPUT);
delay(200);
digitalWrite(RELAY_PIN, HIGH);
digitalWrite(RELAY_PIN_02, HIGH);
digitalWrite(RELAY_PIN_03, HIGH);
digitalWrite(RELAY_PIN_04, HIGH);
}
bool Modules::readTemp()
{
//DS18B20.begin();
Serial.println("--------------------------------------");
DS18B20.requestTemperatures();
temp = DS18B20.getTempCByIndex(0);
Serial.print("Température Dallas =");
Serial.println(temp);
if (temp > 0 && temp < 70) {
return true;
}
return false;
}
void Modules::sleep(int sleepTime)
{
Serial.print("Go to sleep ");
Serial.println(sleepTime);
delay(20);
ESP.deepSleep(sleepTime * 1000000L); // Infini
//sleepWifi();
delay(200);
}
void Modules::relay(int pin, int value)
{
delay(100);
digitalWrite(pin, value);
delay(100);
}

View File

@@ -0,0 +1,28 @@
#ifndef Modules_h
#define Modules_h
#include <Arduino.h>
#include <DallasTemperature.h>
#include "Pins.h"
// ################# Barometre ####
#define ALTITUDE 19.0 // Altitude of SparkFun's HQ in Boulder, CO. in meters
//SFE_BMP180 pressure;
// #####################
class Modules
{
public:
Modules();
bool readTemp();
void sleep(int sleepTime);
void relay(int pin, int value);
private:
public:
double humidity = 0;
double temp = 0;
int end_filament = 0;
};
#endif

View File

@@ -0,0 +1,178 @@
#include "Octoprint.h"
Octoprint::Octoprint(String octoprint, String port, String API)
{
_octoprint = octoprint;
_port = port;
_API = API;
}
boolean Octoprint::connect()
{
// Domo
char _octo[_octoprint.length() + 1];
_octoprint.toCharArray(_octo, _octoprint.length() + 1);
// Port
char portc[_port.length() + 1];
_port.toCharArray(portc, _port.length() + 1);
int _iport = atoi(portc);
boolean connected = _client.connect(_octo, _iport);
Serial.print(_octo);
Serial.print(" ");
Serial.print(_iport);
Serial.print(" ");
Serial.print(" connected ");
Serial.print(connected);
Serial.print(" ");
Serial.println(WiFi.localIP());
return connected;
}
void Octoprint::close()
{
}
void Octoprint::executeJson(String json, String svalue, String nvalue)
{
// Domo
char _octo[_octoprint.length() + 1];
_octoprint.toCharArray(_octo, _octoprint.length() + 1);
// Port
char portc[_port.length() + 1];
_port.toCharArray(portc, _port.length() + 1);
int _iport = atoi(portc);
_client.print("GET " + json); //"GET /json.htm?type=command&param=getuservariables");
if (svalue != "") {
_client.print("&svalue=" + svalue);
}
if (nvalue != "") {
_client.print("&nvalue=" + nvalue);
}
_client.println(" HTTP/1.1");
_client.print("Host: ");
_client.print(_octo);
_client.print(":");
_client.println(_iport);
_client.println("User-Agent: Arduino-ethernet");
_client.println("X-Api-Key:" + _API);
_client.println("Connection: close");
_client.println();
Serial.println("json=" + json);
long interval = 2000;
unsigned long currentMillis = millis(), previousMillis = millis();
while(!_client.available()){
if( (currentMillis - previousMillis) > interval ){
Serial.println("Timeout");
_client.stop();
return;
}
currentMillis = millis();
}
// while (_client.connected())
// {
// if ( _client.available() )
// {
// char str=_client.read();
// Serial.print(str);
// }
// }
while (1)
{
// Avoid WDT reset during long process
yield();
String line = readLine();
if (line == "") {
break;
}
Serial.println(line);
}
}
void Octoprint::executeJsonPost(String json, String postData)
{
if (connect()) {
_client.println("POST " +json + " HTTP/1.1");
_client.println("Host: " + _octoprint + ":" + _port);
_client.println("Cache-Control: no-cache");
_client.println("X-Api-Key:" + _API);
_client.println("Content-Type: application/json");
_client.print("Content-Length: ");
_client.println(postData.length());
_client.println();
_client.println(postData);
long interval = 2000;
unsigned long currentMillis = millis(), previousMillis = millis();
while(!_client.available()){
if( (currentMillis - previousMillis) > interval ){
Serial.println("Timeout");
_client.stop();
return;
}
currentMillis = millis();
}
// while (_client.connected())
// {
// if ( _client.available() )
// {
// char str=_client.read();
// Serial.print(str);
// }
// }
while (1)
{
// Avoid WDT reset during long process
yield();
String line = readLine();
if (line == "") {
break;
}
Serial.println(line);
}
}
}
String Octoprint::getIndexOfString(String data, String separator, int index)
{
int found = 0;
int strIndex[] = { 0, -1 };
int maxIndex = data.length() - 1;
for (int i = 0; i <= maxIndex && found <= index; i++) {
if (data.charAt(i) == separator.charAt(0) || i == maxIndex) {
found++;
strIndex[0] = strIndex[1] + 1;
strIndex[1] = (i == maxIndex) ? i + 1 : i;
}
}
return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
}
String Octoprint::readLine()
{
return _client.readStringUntil('\n');
}

View File

@@ -0,0 +1,33 @@
#ifndef Octoprint_h
#define Octoprint_h
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include "Params.h"
class Octoprint
{
public:
Octoprint(String octoprint, String port, String API);
boolean connect();
void close();
void executeJson(String json, String svalue, String nvalue);
void executeJsonPost(String json, String postData);
//String getIdFromOctoprint();
String readLine();
static String getIndexOfString(String data, String separator, int index);
private:
const char* _pass;
public:
const char* _ssid;
WiFiClient _client;
char _octo[];
int _iport;
String _octoprint;
String _port;
String _API;
};
#endif

View File

@@ -0,0 +1,7 @@
#include "Params.h"
Params::Params()
{
}

View File

@@ -0,0 +1,15 @@
#ifndef Params_h
#define Params_h
#include <Arduino.h>
class Params {
public :
Params();
public :
String esp8266_id;
String esp8266_id_Vcc;
int sleepTime;
};
#endif

View File

@@ -0,0 +1,29 @@
#ifndef Pins_h
#define Pins_h
#include <Arduino.h>
// #define SDA D1
// #define SCL D2
#define ONE_WIRE_BUS D4 // DS18B20 pin
#define RELAY_PIN D5
#define RELAY_PIN_02 D6
#define RELAY_PIN_03 D7
#define RELAY_PIN_04 D0
#define FILAMENT_DETECTION 0
#endif
// #define D0 16
// #define D1 5 // I2C Bus SCL (clock)
// #define D2 4 // I2C Bus SDA (data)
// #define D3 0
// #define D4 2 // Same as "LED_BUILTIN", but inverted logic
// #define D5 14 // SPI Bus SCK (clock)
// #define D6 12 // SPI Bus MISO
// #define D7 13 // SPI Bus MOSI
// #define D8 15 // SPI Bus SS (CS)
// #define D9 3 // RX0 (Serial console)
// #define D10 1 // TX0 (Serial console)

View File

@@ -0,0 +1,657 @@
/*
PubSubClient.cpp - A simple client for MQTT.
Nick O'Leary
http://knolleary.net
*/
#include "PubSubClient.h"
#include "Arduino.h"
PubSubClient::PubSubClient() {
this->_state = MQTT_DISCONNECTED;
this->_client = NULL;
this->stream = NULL;
setCallback(NULL);
}
PubSubClient::PubSubClient(Client& client) {
this->_state = MQTT_DISCONNECTED;
setClient(client);
this->stream = NULL;
}
PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client) {
this->_state = MQTT_DISCONNECTED;
setServer(addr, port);
setClient(client);
this->stream = NULL;
}
PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client, Stream& stream) {
this->_state = MQTT_DISCONNECTED;
setServer(addr,port);
setClient(client);
setStream(stream);
}
PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) {
this->_state = MQTT_DISCONNECTED;
setServer(addr, port);
setCallback(callback);
setClient(client);
this->stream = NULL;
}
PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) {
this->_state = MQTT_DISCONNECTED;
setServer(addr,port);
setCallback(callback);
setClient(client);
setStream(stream);
}
PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client) {
this->_state = MQTT_DISCONNECTED;
setServer(ip, port);
setClient(client);
this->stream = NULL;
}
PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client, Stream& stream) {
this->_state = MQTT_DISCONNECTED;
setServer(ip,port);
setClient(client);
setStream(stream);
}
PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) {
this->_state = MQTT_DISCONNECTED;
setServer(ip, port);
setCallback(callback);
setClient(client);
this->stream = NULL;
}
PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) {
this->_state = MQTT_DISCONNECTED;
setServer(ip,port);
setCallback(callback);
setClient(client);
setStream(stream);
}
PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client) {
this->_state = MQTT_DISCONNECTED;
setServer(domain,port);
setClient(client);
this->stream = NULL;
}
PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client, Stream& stream) {
this->_state = MQTT_DISCONNECTED;
setServer(domain,port);
setClient(client);
setStream(stream);
}
PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) {
this->_state = MQTT_DISCONNECTED;
setServer(domain,port);
setCallback(callback);
setClient(client);
this->stream = NULL;
}
PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) {
this->_state = MQTT_DISCONNECTED;
setServer(domain,port);
setCallback(callback);
setClient(client);
setStream(stream);
}
boolean PubSubClient::connect(const char *id) {
return connect(id,NULL,NULL,0,0,0,0,1);
}
boolean PubSubClient::connect(const char *id, const char *user, const char *pass) {
return connect(id,user,pass,0,0,0,0,1);
}
boolean PubSubClient::connect(const char *id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) {
return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage,1);
}
boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) {
return connect(id,user,pass,willTopic,willQos,willRetain,willMessage,1);
}
boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession) {
if (!connected()) {
int result = 0;
Serial.print("client");
if (domain != NULL) {
result = _client->connect(this->domain, this->port);
} else {
result = _client->connect(this->ip, this->port);
}
Serial.println(result);
if (result == 1) {
nextMsgId = 1;
// Leave room in the buffer for header and variable length field
uint16_t length = MQTT_MAX_HEADER_SIZE;
unsigned int j;
#if MQTT_VERSION == MQTT_VERSION_3_1
uint8_t d[9] = {0x00,0x06,'M','Q','I','s','d','p', MQTT_VERSION};
#define MQTT_HEADER_VERSION_LENGTH 9
#elif MQTT_VERSION == MQTT_VERSION_3_1_1
uint8_t d[7] = {0x00,0x04,'M','Q','T','T',MQTT_VERSION};
#define MQTT_HEADER_VERSION_LENGTH 7
#endif
for (j = 0;j<MQTT_HEADER_VERSION_LENGTH;j++) {
buffer[length++] = d[j];
}
uint8_t v;
if (willTopic) {
v = 0x04|(willQos<<3)|(willRetain<<5);
} else {
v = 0x00;
}
if (cleanSession) {
v = v|0x02;
}
if(user != NULL) {
v = v|0x80;
if(pass != NULL) {
v = v|(0x80>>1);
}
}
buffer[length++] = v;
buffer[length++] = ((MQTT_KEEPALIVE) >> 8);
buffer[length++] = ((MQTT_KEEPALIVE) & 0xFF);
CHECK_STRING_LENGTH(length,id)
length = writeString(id,buffer,length);
if (willTopic) {
CHECK_STRING_LENGTH(length,willTopic)
length = writeString(willTopic,buffer,length);
CHECK_STRING_LENGTH(length,willMessage)
length = writeString(willMessage,buffer,length);
}
if(user != NULL) {
CHECK_STRING_LENGTH(length,user)
length = writeString(user,buffer,length);
if(pass != NULL) {
CHECK_STRING_LENGTH(length,pass)
length = writeString(pass,buffer,length);
}
}
write(MQTTCONNECT,buffer,length-MQTT_MAX_HEADER_SIZE);
lastInActivity = lastOutActivity = millis();
while (!_client->available()) {
unsigned long t = millis();
if (t-lastInActivity >= ((int32_t) MQTT_SOCKET_TIMEOUT*1000UL)) {
_state = MQTT_CONNECTION_TIMEOUT;
_client->stop();
return false;
}
}
uint8_t llen;
uint16_t len = readPacket(&llen);
if (len == 4) {
if (buffer[3] == 0) {
lastInActivity = millis();
pingOutstanding = false;
_state = MQTT_CONNECTED;
return true;
} else {
_state = buffer[3];
}
}
_client->stop();
} else {
_state = MQTT_CONNECT_FAILED;
}
return false;
}
Serial.println("end connect");
return true;
}
// reads a byte into result
boolean PubSubClient::readByte(uint8_t * result) {
uint32_t previousMillis = millis();
while(!_client->available()) {
yield();
uint32_t currentMillis = millis();
if(currentMillis - previousMillis >= ((int32_t) MQTT_SOCKET_TIMEOUT * 1000)){
return false;
}
}
*result = _client->read();
return true;
}
// reads a byte into result[*index] and increments index
boolean PubSubClient::readByte(uint8_t * result, uint16_t * index){
uint16_t current_index = *index;
uint8_t * write_address = &(result[current_index]);
if(readByte(write_address)){
*index = current_index + 1;
return true;
}
return false;
}
uint16_t PubSubClient::readPacket(uint8_t* lengthLength) {
uint16_t len = 0;
if(!readByte(buffer, &len)) return 0;
bool isPublish = (buffer[0]&0xF0) == MQTTPUBLISH;
uint32_t multiplier = 1;
uint16_t length = 0;
uint8_t digit = 0;
uint16_t skip = 0;
uint8_t start = 0;
do {
if (len == 5) {
// Invalid remaining length encoding - kill the connection
_state = MQTT_DISCONNECTED;
_client->stop();
return 0;
}
if(!readByte(&digit)) return 0;
buffer[len++] = digit;
length += (digit & 127) * multiplier;
multiplier *= 128;
} while ((digit & 128) != 0);
*lengthLength = len-1;
if (isPublish) {
// Read in topic length to calculate bytes to skip over for Stream writing
if(!readByte(buffer, &len)) return 0;
if(!readByte(buffer, &len)) return 0;
skip = (buffer[*lengthLength+1]<<8)+buffer[*lengthLength+2];
start = 2;
if (buffer[0]&MQTTQOS1) {
// skip message id
skip += 2;
}
}
for (uint16_t i = start;i<length;i++) {
if(!readByte(&digit)) return 0;
if (this->stream) {
if (isPublish && len-*lengthLength-2>skip) {
this->stream->write(digit);
}
}
if (len < MQTT_MAX_PACKET_SIZE) {
buffer[len] = digit;
}
len++;
}
if (!this->stream && len > MQTT_MAX_PACKET_SIZE) {
len = 0; // This will cause the packet to be ignored.
}
return len;
}
boolean PubSubClient::loop() {
if (connected()) {
unsigned long t = millis();
if ((t - lastInActivity > MQTT_KEEPALIVE*1000UL) || (t - lastOutActivity > MQTT_KEEPALIVE*1000UL)) {
if (pingOutstanding) {
this->_state = MQTT_CONNECTION_TIMEOUT;
_client->stop();
return false;
} else {
buffer[0] = MQTTPINGREQ;
buffer[1] = 0;
_client->write(buffer,2);
lastOutActivity = t;
lastInActivity = t;
pingOutstanding = true;
}
}
if (_client->available()) {
uint8_t llen;
uint16_t len = readPacket(&llen);
uint16_t msgId = 0;
uint8_t *payload;
if (len > 0) {
lastInActivity = t;
uint8_t type = buffer[0]&0xF0;
if (type == MQTTPUBLISH) {
if (callback) {
uint16_t tl = (buffer[llen+1]<<8)+buffer[llen+2]; /* topic length in bytes */
memmove(buffer+llen+2,buffer+llen+3,tl); /* move topic inside buffer 1 byte to front */
buffer[llen+2+tl] = 0; /* end the topic as a 'C' string with \x00 */
char *topic = (char*) buffer+llen+2;
// msgId only present for QOS>0
if ((buffer[0]&0x06) == MQTTQOS1) {
msgId = (buffer[llen+3+tl]<<8)+buffer[llen+3+tl+1];
payload = buffer+llen+3+tl+2;
callback(topic,payload,len-llen-3-tl-2);
buffer[0] = MQTTPUBACK;
buffer[1] = 2;
buffer[2] = (msgId >> 8);
buffer[3] = (msgId & 0xFF);
_client->write(buffer,4);
lastOutActivity = t;
} else {
payload = buffer+llen+3+tl;
callback(topic,payload,len-llen-3-tl);
}
}
} else if (type == MQTTPINGREQ) {
buffer[0] = MQTTPINGRESP;
buffer[1] = 0;
_client->write(buffer,2);
} else if (type == MQTTPINGRESP) {
pingOutstanding = false;
}
} else if (!connected()) {
// readPacket has closed the connection
return false;
}
}
return true;
}
return false;
}
boolean PubSubClient::publish(const char* topic, const char* payload) {
return publish(topic,(const uint8_t*)payload,strlen(payload),false);
}
boolean PubSubClient::publish(const char* topic, const char* payload, boolean retained) {
return publish(topic,(const uint8_t*)payload,strlen(payload),retained);
}
boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength) {
return publish(topic, payload, plength, false);
}
boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) {
if (connected()) {
if (MQTT_MAX_PACKET_SIZE < MQTT_MAX_HEADER_SIZE + 2+strlen(topic) + plength) {
// Too long
return false;
}
// Leave room in the buffer for header and variable length field
uint16_t length = MQTT_MAX_HEADER_SIZE;
length = writeString(topic,buffer,length);
uint16_t i;
for (i=0;i<plength;i++) {
buffer[length++] = payload[i];
}
uint8_t header = MQTTPUBLISH;
if (retained) {
header |= 1;
}
return write(header,buffer,length-MQTT_MAX_HEADER_SIZE);
}
return false;
}
boolean PubSubClient::publish_P(const char* topic, const char* payload, boolean retained) {
return publish_P(topic, (const uint8_t*)payload, strlen(payload), retained);
}
boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) {
uint8_t llen = 0;
uint8_t digit;
unsigned int rc = 0;
uint16_t tlen;
unsigned int pos = 0;
unsigned int i;
uint8_t header;
unsigned int len;
if (!connected()) {
return false;
}
tlen = strlen(topic);
header = MQTTPUBLISH;
if (retained) {
header |= 1;
}
buffer[pos++] = header;
len = plength + 2 + tlen;
do {
digit = len % 128;
len = len / 128;
if (len > 0) {
digit |= 0x80;
}
buffer[pos++] = digit;
llen++;
} while(len>0);
pos = writeString(topic,buffer,pos);
rc += _client->write(buffer,pos);
for (i=0;i<plength;i++) {
rc += _client->write((char)pgm_read_byte_near(payload + i));
}
lastOutActivity = millis();
return rc == tlen + 4 + plength;
}
boolean PubSubClient::beginPublish(const char* topic, unsigned int plength, boolean retained) {
if (connected()) {
// Send the header and variable length field
uint16_t length = MQTT_MAX_HEADER_SIZE;
length = writeString(topic,buffer,length);
uint16_t i;
uint8_t header = MQTTPUBLISH;
if (retained) {
header |= 1;
}
size_t hlen = buildHeader(header, buffer, plength+length-MQTT_MAX_HEADER_SIZE);
uint16_t rc = _client->write(buffer+(MQTT_MAX_HEADER_SIZE-hlen),length-(MQTT_MAX_HEADER_SIZE-hlen));
lastOutActivity = millis();
return (rc == (length-(MQTT_MAX_HEADER_SIZE-hlen)));
}
return false;
}
int PubSubClient::endPublish() {
return 1;
}
size_t PubSubClient::write(uint8_t data) {
lastOutActivity = millis();
return _client->write(data);
}
size_t PubSubClient::write(const uint8_t *buffer, size_t size) {
lastOutActivity = millis();
return _client->write(buffer,size);
}
size_t PubSubClient::buildHeader(uint8_t header, uint8_t* buf, uint16_t length) {
uint8_t lenBuf[4];
uint8_t llen = 0;
uint8_t digit;
uint8_t pos = 0;
uint16_t len = length;
do {
digit = len % 128;
len = len / 128;
if (len > 0) {
digit |= 0x80;
}
lenBuf[pos++] = digit;
llen++;
} while(len>0);
buf[4-llen] = header;
for (int i=0;i<llen;i++) {
buf[MQTT_MAX_HEADER_SIZE-llen+i] = lenBuf[i];
}
return llen+1; // Full header size is variable length bit plus the 1-byte fixed header
}
boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) {
uint16_t rc;
uint8_t hlen = buildHeader(header, buf, length);
#ifdef MQTT_MAX_TRANSFER_SIZE
uint8_t* writeBuf = buf+(MQTT_MAX_HEADER_SIZE-hlen);
uint16_t bytesRemaining = length+hlen; //Match the length type
uint8_t bytesToWrite;
boolean result = true;
while((bytesRemaining > 0) && result) {
bytesToWrite = (bytesRemaining > MQTT_MAX_TRANSFER_SIZE)?MQTT_MAX_TRANSFER_SIZE:bytesRemaining;
rc = _client->write(writeBuf,bytesToWrite);
result = (rc == bytesToWrite);
bytesRemaining -= rc;
writeBuf += rc;
}
return result;
#else
rc = _client->write(buf+(MQTT_MAX_HEADER_SIZE-hlen),length+hlen);
lastOutActivity = millis();
return (rc == hlen+length);
#endif
}
boolean PubSubClient::subscribe(const char* topic) {
return subscribe(topic, 0);
}
boolean PubSubClient::subscribe(const char* topic, uint8_t qos) {
if (qos > 1) {
return false;
}
if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) {
// Too long
return false;
}
if (connected()) {
// Leave room in the buffer for header and variable length field
uint16_t length = MQTT_MAX_HEADER_SIZE;
nextMsgId++;
if (nextMsgId == 0) {
nextMsgId = 1;
}
buffer[length++] = (nextMsgId >> 8);
buffer[length++] = (nextMsgId & 0xFF);
length = writeString((char*)topic, buffer,length);
buffer[length++] = qos;
return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-MQTT_MAX_HEADER_SIZE);
}
return false;
}
boolean PubSubClient::unsubscribe(const char* topic) {
if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) {
// Too long
return false;
}
if (connected()) {
uint16_t length = MQTT_MAX_HEADER_SIZE;
nextMsgId++;
if (nextMsgId == 0) {
nextMsgId = 1;
}
buffer[length++] = (nextMsgId >> 8);
buffer[length++] = (nextMsgId & 0xFF);
length = writeString(topic, buffer,length);
return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-MQTT_MAX_HEADER_SIZE);
}
return false;
}
void PubSubClient::disconnect() {
buffer[0] = MQTTDISCONNECT;
buffer[1] = 0;
_client->write(buffer,2);
_state = MQTT_DISCONNECTED;
_client->flush();
_client->stop();
lastInActivity = lastOutActivity = millis();
}
uint16_t PubSubClient::writeString(const char* string, uint8_t* buf, uint16_t pos) {
const char* idp = string;
uint16_t i = 0;
pos += 2;
while (*idp) {
buf[pos++] = *idp++;
i++;
}
buf[pos-i-2] = (i >> 8);
buf[pos-i-1] = (i & 0xFF);
return pos;
}
boolean PubSubClient::connected() {
boolean rc;
if (_client == NULL ) {
rc = false;
} else {
rc = (int)_client->connected();
if (!rc) {
if (this->_state == MQTT_CONNECTED) {
this->_state = MQTT_CONNECTION_LOST;
_client->flush();
_client->stop();
}
}
}
return rc;
}
PubSubClient& PubSubClient::setServer(uint8_t * ip, uint16_t port) {
IPAddress addr(ip[0],ip[1],ip[2],ip[3]);
return setServer(addr,port);
}
PubSubClient& PubSubClient::setServer(IPAddress ip, uint16_t port) {
this->ip = ip;
this->port = port;
this->domain = NULL;
return *this;
}
PubSubClient& PubSubClient::setServer(const char * domain, uint16_t port) {
this->domain = domain;
this->port = port;
return *this;
}
PubSubClient& PubSubClient::setCallback(MQTT_CALLBACK_SIGNATURE) {
this->callback = callback;
return *this;
}
PubSubClient& PubSubClient::setClient(Client& client){
this->_client = &client;
return *this;
}
PubSubClient& PubSubClient::setStream(Stream& stream){
this->stream = &stream;
return *this;
}
int PubSubClient::state() {
return this->_state;
}

View File

@@ -0,0 +1,173 @@
/*
PubSubClient.h - A simple client for MQTT.
Nick O'Leary
http://knolleary.net
*/
#ifndef PubSubClient_h
#define PubSubClient_h
#include <Arduino.h>
#include "IPAddress.h"
#include "Client.h"
#include "Stream.h"
#define MQTT_VERSION_3_1 3
#define MQTT_VERSION_3_1_1 4
// MQTT_VERSION : Pick the version
//#define MQTT_VERSION MQTT_VERSION_3_1
#ifndef MQTT_VERSION
#define MQTT_VERSION MQTT_VERSION_3_1_1
#endif
// MQTT_MAX_PACKET_SIZE : Maximum packet size
#ifndef MQTT_MAX_PACKET_SIZE
#define MQTT_MAX_PACKET_SIZE 128
#endif
// MQTT_KEEPALIVE : keepAlive interval in Seconds
#ifndef MQTT_KEEPALIVE
#define MQTT_KEEPALIVE 15
#endif
// MQTT_SOCKET_TIMEOUT: socket timeout interval in Seconds
#ifndef MQTT_SOCKET_TIMEOUT
#define MQTT_SOCKET_TIMEOUT 15
#endif
// MQTT_MAX_TRANSFER_SIZE : limit how much data is passed to the network client
// in each write call. Needed for the Arduino Wifi Shield. Leave undefined to
// pass the entire MQTT packet in each write call.
//#define MQTT_MAX_TRANSFER_SIZE 80
// Possible values for client.state()
#define MQTT_CONNECTION_TIMEOUT -4
#define MQTT_CONNECTION_LOST -3
#define MQTT_CONNECT_FAILED -2
#define MQTT_DISCONNECTED -1
#define MQTT_CONNECTED 0
#define MQTT_CONNECT_BAD_PROTOCOL 1
#define MQTT_CONNECT_BAD_CLIENT_ID 2
#define MQTT_CONNECT_UNAVAILABLE 3
#define MQTT_CONNECT_BAD_CREDENTIALS 4
#define MQTT_CONNECT_UNAUTHORIZED 5
#define MQTTCONNECT 1 << 4 // Client request to connect to Server
#define MQTTCONNACK 2 << 4 // Connect Acknowledgment
#define MQTTPUBLISH 3 << 4 // Publish message
#define MQTTPUBACK 4 << 4 // Publish Acknowledgment
#define MQTTPUBREC 5 << 4 // Publish Received (assured delivery part 1)
#define MQTTPUBREL 6 << 4 // Publish Release (assured delivery part 2)
#define MQTTPUBCOMP 7 << 4 // Publish Complete (assured delivery part 3)
#define MQTTSUBSCRIBE 8 << 4 // Client Subscribe request
#define MQTTSUBACK 9 << 4 // Subscribe Acknowledgment
#define MQTTUNSUBSCRIBE 10 << 4 // Client Unsubscribe request
#define MQTTUNSUBACK 11 << 4 // Unsubscribe Acknowledgment
#define MQTTPINGREQ 12 << 4 // PING Request
#define MQTTPINGRESP 13 << 4 // PING Response
#define MQTTDISCONNECT 14 << 4 // Client is Disconnecting
#define MQTTReserved 15 << 4 // Reserved
#define MQTTQOS0 (0 << 1)
#define MQTTQOS1 (1 << 1)
#define MQTTQOS2 (2 << 1)
// Maximum size of fixed header and variable length size header
#define MQTT_MAX_HEADER_SIZE 5
#if defined(ESP8266) || defined(ESP32)
#include <functional>
#define MQTT_CALLBACK_SIGNATURE std::function<void(char*, uint8_t*, unsigned int)> callback
#else
#define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, unsigned int)
#endif
#define CHECK_STRING_LENGTH(l,s) if (l+2+strlen(s) > MQTT_MAX_PACKET_SIZE) {_client->stop();return false;}
class PubSubClient : public Print {
private:
Client* _client;
uint8_t buffer[MQTT_MAX_PACKET_SIZE];
uint16_t nextMsgId;
unsigned long lastOutActivity;
unsigned long lastInActivity;
bool pingOutstanding;
MQTT_CALLBACK_SIGNATURE;
uint16_t readPacket(uint8_t*);
boolean readByte(uint8_t * result);
boolean readByte(uint8_t * result, uint16_t * index);
boolean write(uint8_t header, uint8_t* buf, uint16_t length);
uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos);
// Build up the header ready to send
// Returns the size of the header
// Note: the header is built at the end of the first MQTT_MAX_HEADER_SIZE bytes, so will start
// (MQTT_MAX_HEADER_SIZE - <returned size>) bytes into the buffer
size_t buildHeader(uint8_t header, uint8_t* buf, uint16_t length);
IPAddress ip;
const char* domain;
uint16_t port;
Stream* stream;
int _state;
public:
PubSubClient();
PubSubClient(Client& client);
PubSubClient(IPAddress, uint16_t, Client& client);
PubSubClient(IPAddress, uint16_t, Client& client, Stream&);
PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client);
PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&);
PubSubClient(uint8_t *, uint16_t, Client& client);
PubSubClient(uint8_t *, uint16_t, Client& client, Stream&);
PubSubClient(uint8_t *, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client);
PubSubClient(uint8_t *, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&);
PubSubClient(const char*, uint16_t, Client& client);
PubSubClient(const char*, uint16_t, Client& client, Stream&);
PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client);
PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&);
PubSubClient& setServer(IPAddress ip, uint16_t port);
PubSubClient& setServer(uint8_t * ip, uint16_t port);
PubSubClient& setServer(const char * domain, uint16_t port);
PubSubClient& setCallback(MQTT_CALLBACK_SIGNATURE);
PubSubClient& setClient(Client& client);
PubSubClient& setStream(Stream& stream);
boolean connect(const char* id);
boolean connect(const char* id, const char* user, const char* pass);
boolean connect(const char* id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession);
void disconnect();
boolean publish(const char* topic, const char* payload);
boolean publish(const char* topic, const char* payload, boolean retained);
boolean publish(const char* topic, const uint8_t * payload, unsigned int plength);
boolean publish(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained);
boolean publish_P(const char* topic, const char* payload, boolean retained);
boolean publish_P(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained);
// Start to publish a message.
// This API:
// beginPublish(...)
// one or more calls to write(...)
// endPublish()
// Allows for arbitrarily large payloads to be sent without them having to be copied into
// a new buffer and held in memory at one time
// Returns 1 if the message was started successfully, 0 if there was an error
boolean beginPublish(const char* topic, unsigned int plength, boolean retained);
// Finish off this publish message (started with beginPublish)
// Returns 1 if the packet was sent successfully, 0 if there was an error
int endPublish();
// Write a single byte of payload (only to be used with beginPublish/endPublish)
virtual size_t write(uint8_t);
// Write size bytes from buffer into the payload (only to be used with beginPublish/endPublish)
// Returns the number of bytes written
virtual size_t write(const uint8_t *buffer, size_t size);
boolean subscribe(const char* topic);
boolean subscribe(const char* topic, uint8_t qos);
boolean unsubscribe(const char* topic);
boolean loop();
boolean connected();
int state();
};
#endif

View File

@@ -0,0 +1,890 @@
#include "ServeurWeb.h"
#include <ESP8266WiFi.h>
#include "Pins.h"
ServeurWeb::ServeurWeb()
{
Serial.println("--------------------------------------");
Serial.println("Init ServeurWeb");
//domoticz = _domoticz;
// WifiServer server(80);
//server->begin();
}
void ServeurWeb::loop()
{
//Serial.println("--------------------------------------");
//Serial.println("Loop ServeurWeb");
// read the state of the end button value:
modules->end_filament = digitalRead(FILAMENT_DETECTION);
//Serial.println('fin de filament ' + modules->end_filament);
if ((bcl % (refresh * 60)) == 0) { //DELAI_LECTURE == 0) {
// infos();
nbData += 1;
nbData = nbData % 256;
}
// Check if a client has connected
client = server->available();
if (!client) {
// infos();
// delay(1000);
bcl++;
return;
}
// Read the first line of the request
String req = client.readStringUntil('\r');
Serial.println(req);
// client.flush();
// Match the request
int val = -1; // We'll use 'val' to keep track of both the
// request type (read/set) and value if set.
if (req.indexOf("/admin") != -1) {
val = -3;
//int end = readPage(START_ADDRESS);
//pageAdmin();
pageMenu(PAGE_ADMIN);
} else if (req.indexOf("/graph") != -1) {
pageMenu(PAGE_GRAPH);
} else if (req.indexOf("/reset") != -1) {
client.println("Reset done. SSID, PASS, Domoticz, port & id cleaned.");
delay(100);
} else if (req.indexOf("/ident") != -1) {
ident(req);
} else if (req.indexOf("/status") != -1) {
//printWifiStatus();
pageMenu(PAGE_STATUS);
} else if (req.indexOf("/infos") != -1) {
pageMenu(PAGE_INFOS);
} else if (req.indexOf("/relay_01") != -1) {
client.print("relay_01=");
client.print(val0); //digitalRead(0));
delay(100);
} else if (req.indexOf("/relay_02") != -1) {
client.print("relay_02=");
client.print(val2); //digitalRead(2));
delay(100);
} else if (req.indexOf("/action") != -1) {
// Affectation des variables aux sorties correspondantes
if (req.indexOf("relay_01=false") != -1)
{
val0 = HIGH;
modules->relay(RELAY_PIN, val0);
}
if (req.indexOf("relay_01=true") != -1)
{
val0 = LOW;
modules->relay(RELAY_PIN, val0);
}
if (req.indexOf("relay_02=false") != -1)
{
val2 = HIGH;
digitalWrite(RELAY_PIN_02, val2);
}
if (req.indexOf("relay_02=true") != -1)
{
val2 = LOW;
digitalWrite(RELAY_PIN_02, val2);
}
if (req.indexOf("relay_03=false") != -1)
{
val3 = HIGH;
digitalWrite(RELAY_PIN_03, val3);
}
if (req.indexOf("relay_03=true") != -1)
{
val3 = LOW;
digitalWrite(RELAY_PIN_03, val3);
}
if (req.indexOf("relay_04=false") != -1)
{
val4 = HIGH;
digitalWrite(RELAY_PIN_04, val4);
}
if (req.indexOf("relay_04=true") != -1)
{
val4 = LOW;
digitalWrite(RELAY_PIN_04, val4);
}
Serial.println("Val0=" + String(val0) + " Val2=" + String(val2)
+ " Val3=" + String(val3) + " Val4=" + String(val4));
pageMenu(PAGE_MENU);
} else if (req.indexOf("/menu") != -1) {
//pageMenu();
pageMenu(PAGE_MENU);
} else {
pageMenu(PAGE_MENU);
}
//client.stop();
// The client will actually be disconnected
// when the function returns and 'client' object is detroyed
}
String ServeurWeb::getValueFrom(String request, int deb, int fin) {
int bufLength = ((fin) - (deb + 5)); //the 5 is for the "name=" string
String tmp = request.substring((deb + 5), (fin - 1));
return tmp;
}
char* ServeurWeb::convertToChar(String s, char* buf) {
char c[s.length() + 1];
s.toCharArray(c, s.length() + 1);
return c;
}
void ServeurWeb::infos()
{
int nb = 0;
//WiFiClient client2; // = domoticz->_client;
// Domoticz format /json.htm?type=command&param=udevice&idx=IDX&nvalue=0&svalue=TEMP;HUM;HUM_STAT
// Type
// 0 = Integer, e.g. -1, 1, 0, 2, 10
//1 = Float, e.g. -1.1, 1.2, 3.1
//2 = String
//3 = Date in format DD/MM/YYYY
//4 = Time in 24 hr format HH:MM
//5 = DateTime (but the format is not checked)
// SAve variable "json.htm?type=command&param=saveuservariable&vname=" + domoticz->_macID + "uservariablename&vtype=2&vvalue=uservariablevalue"
// GEt Variables
// http://192.168.0.10:8080/json.htm?type=command&param=getuservariables&idx=4
// // Domo
// char domoticz->_domoc[domoticz.length() + 1];
// domoticz.toCharArray(domoticz->_domoc, domoticz.length() + 1);
// // Port
// char portc[port.length() + 1];
// port.toCharArray(portc, port.length() + 1);
// int domoticz->_iport = atoi(portc);
Serial.print(domoticz->_domoticz);
Serial.print(" ");
Serial.println(domoticz->_port);
Serial.print(" radiateur=");
Serial.print(radiateur);
Serial.print(" temperature=");
Serial.print(temp);
Serial.print(" consigne=");
Serial.print(cons);
Serial.println("");
// Avoid WDT reset during long process
yield();
// -------------------
// LECTURE PARAM
// -------------------
if (radiateur == "") {
Serial.println("Lecture parametre dans domoticz");
if (domoticz->connect()) {
Serial.println("Connected to domoticz");
domoticz->executeJson("/json.htm?type=command&param=getuservariables", "", "");
// Read the first line of the request
while (1) {
// Avoid WDT reset during long process
yield();
String req = domoticz->readLine();
// Serial.println(req);
if (req.indexOf(domoticz->_macID) != -1) {
Serial.println(req);
// Serial.println(req);
req = domoticz->readLine();
req = domoticz->readLine();
String val = req.substring(req.indexOf(":") + 2, req.length() - 1);
Serial.println(val);
val.replace("\"", "");
radiateur = domoticz->getIndexOfString(val, separator, 0);
temp = domoticz->getIndexOfString(val, separator, 1);
cons = domoticz->getIndexOfString(val, separator, 2);
refresh = domoticz->getIndexOfString(val, separator, 3).toInt();
nom = domoticz->getIndexOfString(val, separator, 4);
for (int cpt = 0; cpt < 5; cpt++ ) {
Serial.print(domoticz->getIndexOfString(val, separator, cpt));
}
Serial.println("");
Serial.println("radiateur=" + radiateur);
Serial.println("temp=" + temp);
Serial.println("cons=" + cons);
break;
}
if (req == "" || nb > 500) {
break;
}
nb++;
}
//client2.stop();
delay(100);
}
}
if (radiateur != "") {
if (domoticz->connect()) {
Serial.println("Connected to domoticz lecteur statut radiateur" );
domoticz->executeJson("/json.htm?type=devices&rid=" + radiateur, "", "");
// Read the first line of the request
while (1) {
// Avoid WDT reset during long process
yield();
String req = domoticz->readLine();
if (req.indexOf("\"Status\"") != -1) {
Serial.println(req.substring(req.indexOf(":") + 2));
break;
}
if (req == "" || nb > 500) {
break;
}
nb++;
}
//client2.stop();
delay(100);
}
if (domoticz->connect()) {
Serial.println("Connected to domoticz lecture donnée température" );
domoticz->executeJson("/json.htm?type=devices&rid=723", "","");
// Read the first line of the request
while (1) {
// Avoid WDT reset during long process
yield();
String req = domoticz->readLine();
Serial.println(req);
if (req.indexOf("\"Temp\"") != -1) {
String tmp = req.substring(req.indexOf(":") + 2);
tmp = tmp.substring(0, tmp.indexOf(".") + 2);
Serial.println(tmp);
if (data == "") {
data += tmp;
labels = "\"0\"";
} else {
data += "," + tmp;
if (nbData % 10 == 0) {
labels = labels + "," + "\"" + nbData + "\"";
} else {
labels = labels + "," + "\"" + "\"";
}
}
if (data.length() > 500) {
data = data.substring(data.indexOf(",") + 1);
labels = labels.substring(labels.indexOf(",") + 1);
}
Serial.println(data);
Serial.println(labels);
break;
}
if (req == "" || nb > 500) {
break;
}
nb++;
}
//client2.stop();
delay(100);
}
if (domoticz->connect()) {
Serial.println("Connected to domoticz lecteur consigne" );
domoticz->executeJson("/json.htm?type=devices&rid=" + cons, "", "");
// Read the first line of the request
while (1) {
// Avoid WDT reset during long process
yield();
String req = domoticz->readLine();
if (req.indexOf("\"SetPoint\"") != -1) {
String value = req.substring(req.indexOf(":") + 2);
//value = .substring(req.indexOf(":") + 1);
value.trim();
Serial.println(value);
break;
}
if (req == "" || nb > 500) {
break;
}
nb++;
}
//client2.stop();
delay(100);
}
}
// Avoid WDT reset during long process
yield();
Serial.println("Fin infos");
// Avoid WDT reset during long process
yield();
}
void ServeurWeb::printWifiStatus() {
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print your WiFi shield's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
// PAge
client.println("<p>Connected to ");
client.println(WiFi.SSID());
client.println("</p><p>Ip: ");
client.println(ip);
client.println("</p><p>Force du signal:");
client.println(rssi);
client.println(" dBm</p>");
client.println("<p>Domoticz:");
client.println(domoticz->_domoticz);
client.println(":");
client.println(domoticz->_port);
client.println("</p>");
//
// client.println("<div class='c100 p25 dark orange'>");
// client.println(" <span>25%</span>");
// client.println(" <div class='slice'>");
// client.println(" <div class='bar'></div>");
// client.println(" <div class='fill'></div>");
// client.println(" </div>");
// client.println("</div>");
client.println("<button class='boutonTemp' onclick='click()'>" + temp + "</button>");
client.println("<button class='boutonCons' onclick='click()'>" + cons + "</button>");
}
////////////////////////////////////////////
////// PAGE MENU
////////////////////////////////////////////
void ServeurWeb::pageMenu(int page) {
client.println("<html>");
client.println("<head>");
client.println("<link rel=\"shortcut icon\" href=\"http://" + domoticz->_domoticz + ":" + domoticz->_port + "/favicon.ico\">");
if (page == PAGE_GRAPH) {
client.println("<meta http-equiv=\"refresh\" content=\"60\" >");
}
if (page == PAGE_MENU) {
// // Look des champs de saisis
// client.println("<link rel=\"stylesheet\" type=\"text/css\" media=\"all\" href=\"http://" + domoticz->_domoticz + "/ESP8266/css/styles.css\">");
// // Look Bouton toggle
// client.println("<link rel=\"stylesheet\" type=\"text/css\" media=\"all\" href=\"http://" + domoticz->_domoticz + "/ESP8266/css/toggles-soft.css\">");
}
menuStyle(page);
client.println("</head>");
menuBody(page);
client.println("</html>\n\r");
}
void ServeurWeb::menuBody(int page) {
client.println("<body>");
client.println("<header role='banner'>");
client.println("<div class='wrapper'>");
client.print("<h1> ");
client.print(nom + " " + domoticz->_macID);
client.println("</h1>");
client.println("<nav id='nav' role='navigation'>");
client.println("<div class='show_menu_btn' data-target='#nav ul' data-shown-text='Hide menu' data-hidden-text='Show menu' >Show menu</div>");
client.println("<ul>");
client.println("<li><a href='/menu'>Menu</a></li>");
client.println("<li><a href='/admin'>Admin</a></li>");
//client.println("<li><a href='/infos'>Infos</a></li>");
client.println("<li><a href='/status'>Status</a></li>");
//client.println("<li><a href='/reset'>Reset</a></li>");
client.println("<li><a href='/graph'>Graph</a></li>");
//client.println("<li><a href='/aide'>Aide</a></li>");
client.println("</ul>");
client.println("</nav>");
client.println("</div>");
client.println("</header>");
client.println("<main role='main'>");
client.println("<div class='wrapper'>");
if (page == PAGE_MENU) {
client.print("<form><div><input type=\"checkbox\" id=\"relay_01\" onclick=\"handleClick(this);\" ");
if (val0 == 0) {
client.print("unchecked");
} else {
client.print("checked");
}
client.println("><label for=\"relay_01\" onclick=\"relay_01();\">Relai 1</label></div></form>");
client.println("<form><div><input type=\"checkbox\" id=\"relay_02\" onclick=\"handleClick(this);\" ");
if (val2 == 0) {
client.print("unchecked");
} else {
client.print("checked");
}
client.println("><label for=\"relay_02\" onclick=\"relay_02();\">Relai 2</label></div></form>");
client.println("<form><div><input type=\"checkbox\" id=\"relay_03\" onclick=\"handleClick(this);\" ");
if (val3 == 0) {
client.print("unchecked");
} else {
client.print("checked");
}
client.println("><label for=\"relay_03\" onclick=\"relay_03();\">Relai 3</label></div></form>");
client.println("<form><div><input type=\"checkbox\" id=\"relay_04\" onclick=\"handleClick(this);\" ");
if (val4 == 0) {
client.print("unchecked");
} else {
client.print("checked");
}
client.println("><label for=\"relay_04\" onclick=\"relay_04();\">Relai 4</label></div></form>");
} else if (page == PAGE_ADMIN) {
client.println( "<form action='/ident' method='get'>");
client.println( "<script type='text/javascript'>\nfunction showValue(newValue)\n{\ndocument.getElementById('text').innerHTML=newValue;\n}\n</script>");
client.println( "<div>");
client.println( "<label for='name'>SSID:</label>");
String ssid = String(domoticz->_ssid);
// sprintf (domoticz->_ssid, "%18x", ssid);
client.println( "<input type='text' id='name' name='name' value='" + ssid + "'/>");
client.println( "</div>");
client.println( "<div>");
client.println( "<label for='pass'>Password:</label>");
String pass = String(domoticz->_pass);
client.println( "<input type='password' id='pass' name='pass' value='" + pass + "'/>");
client.println( "</div>");
client.println( "<div>");
client.println( "<label for='domo'>Domoticz:</label>");
client.println( "<input type='text' id='domo' name='domo' value='" + domoticz->_domoticz + "'/>"); // />");
client.println( "</div>");
client.println( "<div>");
client.println( "<label for='port'>Port:</label>");
client.println( "<input type='text' id='port' name='port' value='" + domoticz->_port + "'/>");
client.println( "</div>");
// client.println( "<div>");
// client.println( "<label for='radi'>Id Radiateur:</label>");
// client.println( "<input type='radi' id='radi' name='radi' value='" + radiateur + "'/>");
// client.println( "</div>");
// client.println( "<div>");
// client.println( "<label for='temp'>Id Thermometre:</label>");
// client.println( "<input type='temp' id='temp' name='temp' value='" + temp + "'/>");
// client.println( "</div>");
// client.println( "<div>");
// client.println( "<label for='cons'>Id Consigne:</label>");
// client.println( "<input type='cons' id='cons' name='cons' value='" + cons + "'/>");
// client.println( "</div>");
client.println( "<div class='button'>");
client.println( "<button name=H type='submit'>Ok</button>");
client.println( "</div>");
client.println( "</form>");
} else if (page == PAGE_STATUS) {
client.println("<article>");
printWifiStatus();
client.println("</article>");
} else if (page == PAGE_GRAPH) {
graph();
} else if (page == PAGE_INFOS) {
infos();
}
client.println(" </div>");
client.println("</main>");
client.println("<script>");
client.println("var show_menu=document.querySelector('.show_menu_btn'),viewport_width=document.documentElement.clientWidth,menu=document.querySelector('#nav ul');600>viewport_width&&(menu.style.display='none'),window.addEventListener('resize',function(){var e=document.documentElement.clientWidth;menu.style.display=e>599?'block':'none'}),show_menu.addEventListener('click',function(){var e=document.querySelector(show_menu.getAttribute('data-target'));'none'==e.style.display?(e.style.display='block',show_menu.innerHTML=show_menu.getAttribute('data-shown-text')):(e.style.display='none',show_menu.innerHTML=show_menu.getAttribute('data-hidden-text'))});");
//menuJS();
// Fonction pour les voutons
//client.println("function click(){$(function() {$( '#dialog' ).dialog({width : 250, height: 180, modal : true }); }); }");
client.println("</script>");
if (page == PAGE_GRAPH) {
// client.println("<script src=\"http://" + domoticz->_domoticz + "/" + jsPath + "/" + chartName + "\"></script>");
client.println("<script src=\"https://www.chartjs.org/dist/2.9.3/Chart.min.js\"></script>");
}
else if (page == PAGE_MENU) {
client.println("<script>");
client.println("function relay_04() {document.getElementById(\"relay_04\").click();}");
client.println("function relay_03() {document.getElementById(\"relay_03\").click();}");
client.println("function relay_02() {document.getElementById(\"relay_02\").click();}");
client.println("function relay_01() {document.getElementById(\"relay_01\").click();}");
client.println("function handleClick(cb) {post_to_url(cb, \"/action\", { submit: \"submit\" });}");
client.println("function post_to_url(x, path, params, method) {");
client.println("method = \"get\"; var form = document.createElement(\"form\");");
//1client.println("var x = document.getElementById(\"relay_01\");");
// client.println("var x2 = document.getElementById(\"relay_02\");");
client.println("form._submit_function_ = form.submit;");
client.println("form.setAttribute(\"method\", method);");
client.println("form.setAttribute(\"action\", path);");
client.println("var hiddenField = document.createElement(\"input\");");
client.println("hiddenField.setAttribute(\"type\", \"hidden\");");
client.println("hiddenField.setAttribute(\"name\", x.id);");
client.println("hiddenField.setAttribute(\"value\", x.checked);");
client.println("form.appendChild(hiddenField);");
client.println("document.body.appendChild(form);");
// client.println("var hiddenField2 = document.createElement(\"input\");");
// client.println("hiddenField2.setAttribute(\"type\", \"hidden\");");
// client.println("hiddenField2.setAttribute(\"name\", x2.id);");
// client.println("hiddenField2.setAttribute(\"value\", x2.checked);");
// client.println("form.appendChild(hiddenField2);");
// client.println("document.body.appendChild(form);");
client.println("form._submit_function_(); }</script>");
}
client.println("</body>");
}
void ServeurWeb::menuStyle(int page) {
// menuStyle.css
client.println("<style>");
client.println( "a,abbr,acronym,address,applet,article,aside,audio,b,big,blockquote,body,canvas,caption,center,cite,code,dd,del,details,dfn,div,dl,dt,em,embed,fieldset,figcaption,");
client.println( "figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,html,i,iframe,img,ins,kbd,label,legend,li,mark,menu,nav,object,ol,output,p,pre,q,ruby,s,samp,section,small,span,");
client.println( "strike,strong,sub,summary,sup,table,tbody,td,tfoot,th,thead,time,tr,tt,u,ul,var,video{margin:0;padding:0;border:0;font:inherit;vertical-align:baseline}");
client.println( "article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}nav ul{list-style:none}blockquote,q{quotes:none}blockquote:");
client.println( "after,blockquote:before,q:after,q:before{content:'';");
client.println( "content:none}table{border-collapse:collapse;border-spacing:0}h1{font-size:1.5em;font-weight:700;padding:.5em 0;letter-spacing:1px}@media screen and ");
client.println( "(max-width:599px){h1{text-align:center}}h2{font-size:1.25em;font-weight:700;line-height:1.2;padding:.5em 0}p{font-size:1em;padding:0 0 1em}a{color:#555;");
client.println( "text-decoration:none;border-bottom:1px solid #555}a:hover{color:#88b47f;border-bottom:1px solid #88b47f}*{-moz-box-sizing:border-box;-webkit-box-sizing:");
client.println( "border-box;box-sizing:border-box;-webkit-text-size-adjust:auto}body{font-family:sans-serif;font-size:100%;text-align:center;line-height:1.5;background:");
client.println( "#f8f7f0;color:#555}.wrapper{width:90%;max-width:50em;margin:0 auto;text-align:left;overflow:hidden}");
client.println( "header{margin-bottom:1em;padding-bottom:1em;background:#57575f;color:#fff}@media screen and (max-width:599px){.no-js .show_menu_btn{display:none}.js .show_menu_btn,.no-js #nav ul{display:block}.js #nav ul{display:none}}@media screen and (min-width:600px){.show_menu_btn{display:none}#nav ul{display:block}}.show_menu_btn{width:35%;margin:0 auto;padding:.3em;cursor:pointer;text-align:center;background:#88b47f}#nav ul{margin:1em 0}#nav ul li{padding:.5em}#nav ul li:hover{background:#88b47f}#nav ul a{display:block;font-size:1em;color:#eee;border-bottom:none}@media screen and (max-width:599px){#nav ul{display:block}#nav ul li{display:block;text-align:center;border-bottom:1px solid #6f6f7a}}@media screen and (min-width:600px){#nav{overflow:hidden}#nav ul li{width:7em;float:left;margin-right:1em}}");
//Bouton
client.println( ".boutonTemp {width:85px;height:85px;background:#fafafa;box-shadow:2px 2px 8px #aaa;font:bold 13px Arial;border-radius:50%;color:#555;}");
client.println( ".boutonCons {width:85px;height:85px;background:#cc0000;font:bold 13px Arial;border-radius:50%;border:none;color:#fff;}");
// PAGE MENU
client.println("input[type=\"checkbox\"] {display: none;}");
client.println("input[type=\"checkbox\"] + label {display:inline-block; line-height:normal; cursor:pointer; padding: 3px 14px;");
client.println("background-color: #EFEFEF;border-radius: 4px;border: 1px solid #D0D0D0;margin: 40px 100px 10px 40px;");
client.println("}input[type=\"checkbox\"] + label:hover {border-color: #000;background-color: #911;color: #fff;}");
client.println("input[type=\"checkbox\"]:checked + label {border-color: #000;background-color: #888;color: #fff;}");
client.println("</style>");
}
///////////////////////////////////////////////////
// PAGE ADMIN
///////////////////////////////////////////////////
void ServeurWeb::pageAdmin() {
client.println("<html>");
style();
body();
client.println("</html>\n\r");
}
void ServeurWeb::body() {
// body.html
client.println( "<body>");
client.println( "<form action='/ident' method='get'>");
client.println( "<script type='text/javascript'>\nfunction showValue(newValue)\n{\ndocument.getElementById('text').innerHTML=newValue;\n}\n</script>");
client.println( "<div>");
client.println( "<label for='name'>SSID:</label>");
client.println( "<input type='text' id='name' name='name' />");
client.println( "</div>");
client.println( "<div>");
client.println( " <label for='pass'>Password:</label>");
client.println( " <input type='password' id='pass' name='pass' />");
client.println( "</div>");
client.println( "<div>");
client.println( " <label for='domo'>Domoticz:</label>");
client.println( " <input type='text' id='domo' name='domo' />");
client.println( " <label for='port'>Port:</label>");
client.println( " <input type='text' id='port' name='port' />");
client.println( "</div>");
client.println( "<div>");
client.println( " <label for='radi'>Id Radiateur:</label>");
client.println( " <input type='radi' id='radi' name='radi' />");
client.println( "</div>");
client.println( "<div class='button'>");
client.println( " <button name=H type='submit'>Ok</button>");
client.println( "</div>");
client.println( "</form>");
client.println( "</body>");
}
void ServeurWeb::style() {
// style.css
client.println( "<style>");
client.println( "form {");
// client.println( " /* Just to center the form on the page */");
client.println( " margin: 0 auto;");
client.println( " width: 400px;");
client.println( "");
// client.println( " /* To see the limits of the form */");
client.println( " padding: 1em;");
client.println( " border: 1px solid #CCC;");
client.println( " border-radius: 1em;");
client.println( "}");
client.println( "");
client.println( "div + div {");
client.println( " margin-top: 1em;");
client.println( "}");
client.println( "");
client.println( "label {");
// client.println( " /* To make sure that all label have the same size and are properly align */");
client.println( " display: inline-block;");
client.println( " width: 90px;");
client.println( " text-align: right;");
client.println( "}");
client.println( "");
client.println( "input, textarea {");
// client.println( " /* To make sure that all text field have the same font settings");
// client.println( " By default, textarea are set with a monospace font */");
client.println( " font: 1em sans-serif;");
client.println( "");
// client.println( " /* To give the same size to all text field */");
client.println( " width: 300px;");
client.println( "");
client.println( " -moz-box-sizing: border-box;");
client.println( " box-sizing: border-box;");
client.println( "");
// client.println( " /* To harmonize the look & feel of text field border */");
client.println( " border: 1px solid #999;");
client.println( "}");
client.println( "");
client.println( "input:focus, textarea:focus {");
// client.println( " /* To give a little highligh on active elements */");
client.println( " border-color: #000;");
client.println( "}");
client.println( "");
client.println( "textarea {");
// client.println( " /* To properly align multiline text field with their label */");
client.println( " vertical-align: top;");
client.println( "");
// client.println( " /* To give enough room to type some text */");
client.println( " height: 5em;");
client.println( "");
// client.println( " /* To allow users to resize any textarea vertically");
// client.println( " It works only on Chrome, Firefox and Safari */");
client.println( " resize: vertical;");
client.println( "}");
client.println( "");
client.println( ".button {");
// client.println( " /* To position the buttons to the same position of the text fields */");
// client.println( " padding-left: 90px; /* same size as the label elements */");
client.println( "}");
client.println( "");
client.println( "button {");
// client.println( " /* This extra magin represent the same space as the space between");
// client.println( " the labels and their text fields */");
client.println( " margin-left: .5em;");
client.println( "}");
client.println(".toggle-slide {");
client.println(" overflow: hidden;");
client.println(" cursor: pointer;");
client.println(" -webkit-touch-callout: none;");
client.println(" -webkit-user-select: none;");
client.println(" -khtml-user-select: none;");
client.println(" -moz-user-select: none;");
client.println(" -ms-user-select: none;");
client.println(" user-select: none;");
client.println(" direction: ltr;");
client.println("}");
client.println(".toggle-slide .toggle-on,.toggle-slide .toggle-off,.toggle-slide .toggle-blob {");
client.println(" float: left;");
client.println("}");
client.println(".toggle-slide .toggle-blob {");
client.println(" position: relative;");
client.println(" z-index: 99;");
client.println(" cursor: hand;");
client.println(" cursor: grab;");
client.println(" cursor: -moz-grab;");
client.println(" cursor: -webkit-grab;");
client.println("}");
client.println( "</style>");
}
void ServeurWeb::graph() {
// infos();
client.println( "<canvas id='canvas' ></canvas>");
client.println( "<script>");
client.println( "var randomScalingFactor = function(){ return Math.round(Math.random()*100)};");
client.println( "var config = {");
client.println( "type: 'line',");
client.println( " data: {");
client.print( "labels : ["); //\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\"],");
client.print(domoticz->labels);
client.println("],");
client.println( "datasets : [");
client.println( "{");
client.println( "label: \"My First dataset\",");
client.println( " fillColor : \"rgba(220,220,220,0.2)\",");
client.println( " strokeColor : \"rgba(220,220,220,1)\",");
client.println( " pointColor : \"rgba(220,220,220,1)\",");
client.println( " pointStrokeColor : \"#fff\",");
client.println( " pointHighlightFill : \"#fff\",");
client.println( " pointHighlightStroke : \"rgba(220,220,220,1)\",");
client.print( " data : [");
// randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor()
client.print(domoticz->data);
client.print("]}");
client.println( " ]}};");
client.println( "window.onload = function(){");
client.println( " var ctx = document.getElementById(\"canvas\").getContext(\"2d\");");
client.println( " window.myLine = new Chart(ctx, config);");
// client.println( " responsive: true, animation:true});");
client.println( "}");
client.println( "</script>");
}
//String domoticz->getIndexOfString(String data, String separator, int index)
//{
// int found = 0;
// int strIndex[] = { 0, -1 };
// int maxIndex = data.length() - 1;
//
// for (int i = 0; i <= maxIndex && found <= index; i++) {
// if (data.charAt(i) == separator.charAt(0) || i == maxIndex) {
// found++;
// strIndex[0] = strIndex[1] + 1;
// strIndex[1] = (i == maxIndex) ? i+1 : i;
// }
// }
// return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
//}
void ServeurWeb::ident(String req) {
// Return : ident?name=jjjjj&pass=kkkk&domo&H=
int posName = req.indexOf("name");
int posPass = req.indexOf("pass", posName);
int posDomo = req.indexOf("domo", posPass);
int posPort = req.indexOf("port", posDomo);
// int posRadi = req.indexOf("radi", posPort);
// int posTemp = req.indexOf("temp", posRadi);
// int posCons = req.indexOf("cons", posTemp);
// int End = req.indexOf("H", posCons);
//if (End < 0) {
int End = req.length() + 1;
//}
//ssid
String ssid = getValueFrom(req, posName, posPass);
char ssidc[ssid.length() + 1];
ssid.toCharArray(ssidc, ssid.length() + 1);
//Password
String pass = getValueFrom(req, posPass, posDomo);
char passc[pass.length() + 1];
pass.toCharArray(passc, pass.length() + 1);
// Domo
String domo = getValueFrom(req, posDomo, posPort);
char domoc[domo.length() + 1];
domo.toCharArray(domoc, domo.length() + 1);
// Port
String port = getValueFrom(req, posPort, End); //posRadi);
char portc[port.length() + 1];
port.toCharArray(portc, port.length() + 1);
// // Radiateur
// String radi = getValueFrom(req, posRadi, posTemp);
// char radic[radi.length() + 1];
// radi.toCharArray(radic, radi.length() + 1);
// // Thermometre
// String temp = getValueFrom(req, posTemp, posCons);
// char tempc[temp.length() + 1];
// temp.toCharArray(tempc, temp.length() + 1);
// // Consigne
// String cons = getValueFrom(req, posCons, End);
// char consc[cons.length() + 1];
// cons.toCharArray(consc, cons.length() + 1);
//Domoticz domo("192.168.1.3", "81", "Livebox-37cc", "8A6060920A8A86896F770F2C47");
// boolean connected = connectToWifi(ssidc, passc);
// client.flush();
// // Prepare the response. Start with the common header:
String s = "HTTP/1.1 200 OK\r\n";
s += "Content-Type: text/html\r\n\r\n";
s += "<!DOCTYPE HTML>\r\n<html>\r\n";
//s += "Connexion en-cours.";
if (true) {
s += "WiFi connected\n";
// Start the server
// server.begin();
// s+="Server started\n";
// Print the IP address
s += "Use this URL to connect: ";
s += "http://";
//s += WiFi.localIP();
s += "/_n";
} else {
s += "Connexion impossible";
}
s += "</html>\n";
client.println(s);
delay(200);
}

View File

@@ -0,0 +1,82 @@
#ifndef ServeurWeb_h
#define ServeurWeb_h
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include "Domoticz.h"
#include "Params.h"
#include "Modules.h"
#include "Pins.h"
#define PAGE_MENU 0
#define PAGE_ADMIN 1
#define PAGE_STATUS 2
#define PAGE_INFOS 3
#define PAGE_GRAPH 4
#define DELAI_LECTURE 120
class ServeurWeb
{
public:
ServeurWeb();
//void setup();
void loop();
private:
boolean connectToWifi();
//void initHardware();
char* convertToChar(String s, char* buf);
void infos();
void menuBody(int page);
void pageAdmin();
void pageMenu(int page);
void printWifiStatus();
//void setupWiFi();
void body();
String getValueFrom(String request, int deb, int fin);
void menuStyle(int page);
void style();
void graph();
void ident(String req);
public:
Domoticz* domoticz;
Modules* modules;
// WiFiClient _client;
String radiateur = ""; //"217";
String temp = ""; //"281";
String cons = ""; //"212";
String jsPath = "/ESP8266/js/";
String jqueryName = "jquery.js";
String chartName = "chart.js";
String AP_NameString = "";
int nbData = 0;
String data = "22.3,22.3,22.3,22.3";
String labels = "0,1,2,3";
int bcl = 0;
int val0;
int val2;
int val3;
int val4;
String separator = ",";
String nom = "";
int refresh = 2;
WiFiClient client;
WiFiServer* server;
};
#endif
// // Ordre dans Domoticz
// // Radiateur Temp Consigne
// //Manon 217 281 212
// //Théo 219 335 211
// //Chambre 218 254 213
// //Bureau 163 260 214

View File

@@ -0,0 +1,757 @@
// -------------------------------------------------------------
//
// Fichier principal de votre Box compatible Somfy RTS ou Chacon Dio
// Version 1.1.0
// Mise à jour par TOST Corp. le 02 janvier 2020
// www.tostcorp.com/boxsomfyrts
//
// -------------------------------------------------------------
#include "config.h"
// #include "Somfy.h"
void blink_function();
Ticker mqtt_error_timer(blink_function, 10, 11);
Ticker blink_timer(blink_function, 200, 21);
Ticker publish_timer(blink_function, 10, 11);
void receivedCallback(char* topic, byte* payload, unsigned int length);
Somfy::Somfy()
{
}
void Somfy::init()
{
// USB serial port
delay(100);
while(! Serial);
Serial.println(" ------------------------------------------------");
Serial.println("| |");
Serial.println("| TOST Corp. Box V1.0.2 - Copyright 2018-2020 |");
Serial.println("| |");
Serial.println(" ------------------------------------------------");
Serial.println("");
Serial.println("Available features:");
Serial.println("1 SOMFY RTS");
Serial.println("2 CHACON DiO 1.0");
Serial.println("");
Serial.println("Starting the Box...");
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
// Open the output for 433.42MHz transmitter
pinMode(PORT_TX, OUTPUT);
// Open the output for 433.92MHz transmitter
pinMode(PORT_DIO_TX, OUTPUT);
SIG_LOW;
digitalWrite(PORT_DIO_TX, LOW);
String device_id = WiFi.macAddress();
// Remove :
while (device_id.indexOf(':') != -1)
{
int index_to_remove = device_id.indexOf(':');
device_id.remove(index_to_remove, 1);
}
Serial.print("Box ID: ");
Serial.println(device_id);
// Connect to WiFi
Serial.print("WiFi connection to ");
Serial.print(wifi_ssid);
Serial.print(" ");
WiFi.begin(wifi_ssid, wifi_password);
WiFi.hostname("ESP8266-somfy");
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to WiFi | IP adress ");
Serial.println(WiFi.localIP());
// Configure MQTT
PubSubClient _mqtt(wifiClient);
mqtt = _mqtt;
mqtt.setServer(mqtt_server, mqtt_port);
//mqtt.setCallback(receivedCallback);
mqtt.setCallback([this] (char* topic, byte* payload, unsigned int length) {
this->receivedCallback(topic, payload, length);
});
EEPROM.begin(1024);
// Print out all the configured remotes.
// Also reset the rolling codes for ESP8266 if needed.
Serial.print("");
Serial.println("Read the configuration...");
if (update_database)
{
clean_database(device_id);
}
for ( REMOTE remote : remotes )
{
Serial.print("SOMFY RTS: ");
Serial.print(remote.mqtt_topic);
Serial.print(" | number: ");
Serial.print(remote.id, HEX);
Serial.print(" | rolling code: ");
unsigned int current_code;
if ( reset_rolling_codes )
{
EEPROM.put( remote.eeprom_address, remote.default_rolling_code );
EEPROM.commit();
}
EEPROM.get( remote.eeprom_address, current_code );
Serial.print( current_code );
Serial.print(" | description: ");
Serial.println( remote.description );
// Add to database
if (update_database)
{
add_to_database(device_id, remote.mqtt_topic, remote.description, "somfy_rts", remote.device_group);
}
}
for ( DIO_REMOTE dio_remote : dio_remotes )
{
Serial.print("CHACON DiO: ");
Serial.print(dio_remote.mqtt_topic);
Serial.print(" | number: ");
Serial.print(dio_remote.id, HEX);
Serial.print(" | description: ");
Serial.println(dio_remote.description);
// Add to database
if (update_database)
{
add_to_database(device_id, dio_remote.mqtt_topic, dio_remote.description, "chacon_dio_1.0", dio_remote.device_group);
}
} // End of for
Serial.print("");
digitalWrite(LED_BUILTIN, HIGH);
blink_timer.start();
}
void Somfy::loop()
{
publish_timer.update();
// Reconnect MQTT if needed
if ( !mqtt.connected() )
{
mqttconnect();
// We are connected stop blinking to Wifi
blink_timer.stop();
Serial.println("The box is ready.\n");
Serial.println("");
}
mqtt.loop();
loopSerial();
delay(100);
}
void Somfy::mqttconnect()
{
// Loop until reconnected
while ( !mqtt.connected() )
{
Serial.print("Connecting to MQTT ...");
Serial.print(mqtt_id);
Serial.print(mqtt_user);
Serial.print(mqtt_password);
Serial.print(status_topic);
// Connect to MQTT, with retained last will message "offline"
if (mqtt.connect(mqtt_id, mqtt_user, mqtt_password, status_topic, 1, 1, "offline")) {
Serial.println(" Connected.");
Serial.print("Suscribe to MQTT .");
// Subscribe to the topic of each remote with QoS 1
for ( REMOTE remote : remotes ) {
mqtt.subscribe(remote.mqtt_topic, 1);
mqtt.subscribe(remote.device_group, 1);
Serial.print(".");
// Serial.print("\nLOG - Subscribed to SOMFY RTS topic: ");
// Serial.println(remote.device_group);
}
// Subscribe to the topic of each remote with QoS 1
for ( DIO_REMOTE remote : dio_remotes ) {
mqtt.subscribe(remote.mqtt_topic, 1);
mqtt.subscribe(remote.device_group, 1);
Serial.print(".");
// Serial.print("\nLOG - Subscribed to DIO topic: ");
// Serial.println(remote.mqtt_topic);
}
// Update status, message is retained
mqtt.publish(status_topic, "online", true);
Serial.println("Done.");
}
else
{
Serial.print("ERR - Failed, status code = ");
Serial.print(mqtt.state());
Serial.println(" Try again in 5 seconds");
// Wait 5 seconds before retrying
blink_blue_light(5000, 200);
}
}
blink_blue_light(500, 50);
}
void Somfy::receivedCallback(char* topic, byte* payload, unsigned int length) {
char command = *payload; // 1st byte of payload
bool commandIsValid = false;
bool dioCommandIsValid = false;
String s_topic = String(topic);
REMOTE currentRemote;
REMOTE remote;
// DIO_REMOTE dio_remote;
DIO_REMOTE dio_currentRemote;
Serial.print("MQTT message received: ");
digitalWrite(BUILTIN_LED, LOW);
publish_timer.start();
Serial.println(topic);
Serial.print("Payload: ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
// Somfy command is valid if the payload contains one of the chars below AND the topic corresponds to one of the remotes
if ( length == 1 && ( command == 'u' || command == 's' || command == 'd' || command == 'p' ) )
{
Serial.println("SOMFY RTS command received");
int nb_remotes = sizeof remotes/sizeof remotes[0];
for (int i=0; i<nb_remotes; i++)
{
remote = remotes[i];
String s_mqtt_topic = String(remote.mqtt_topic);
String s_device_group = String(remote.device_group);
// if ( strcmp(remote.mqtt_topic, s_topic) == 0 )
if ( s_mqtt_topic.compareTo(s_topic) == 0 )
{
commandIsValid = true;
send_somfy_command(command, remote, false);
}
// if ( strcmp(remote.device_group, s_topic) == 0 )
else if ( s_device_group.compareTo(s_topic) == 0 )
{
Serial.print("SOMFY RTS command is grouped ");
Serial.println(remote.mqtt_topic);
commandIsValid = true;
send_somfy_command(command, remote, true);
}
} // End of for
}
// DIO command
if ( length ==1 && ( command == '1' || command == '0' ) )
{
Serial.println("DiO command received");
for ( DIO_REMOTE dio_remote : dio_remotes )
{
String s_mqtt_topic = String(dio_remote.mqtt_topic);
String s_device_group = String(dio_remote.device_group);
// Single command
// if ( strcmp(dio_remote.mqtt_topic, topic) == 0 )
if ( s_mqtt_topic.compareTo(s_topic) == 0 )
{
dioCommandIsValid = true;
send_dio_command(command, dio_remote, false);
}
// Multiple command
// else if ( strcmp(dio_remote.device_group, topic) == 0 )
else if ( s_device_group.compareTo(s_topic) == 0 )
{
Serial.println("DiO command is grouped");
dioCommandIsValid = true;
send_dio_command(command, dio_remote, true);
}
} // End of for
}
}
void Somfy::send_somfy_command(char command, REMOTE currentRemote, bool group)
{
if ( command == 'u' )
{
Serial.println("COMMAND - Up"); // Somfy is a French company, after all.
BuildFrame(frame, HAUT, currentRemote);
}
else if ( command == 's' )
{
Serial.println("COMMAND - Stop");
BuildFrame(frame, STOP, currentRemote);
}
else if ( command == 'd' )
{
Serial.println("COMMAND - Down");
BuildFrame(frame, BAS, currentRemote);
}
else if ( command == 'p' )
{
Serial.println("COMMAND - Prog");
BuildFrame(frame, PROG, currentRemote);
}
Serial.println("");
SendCommand(frame, 2);
for ( int i = 0; i<2; i++ ) {
SendCommand(frame, 7);
}
// Send the MQTT ack message
String ackString = "id: 0x";
ackString.concat( String(currentRemote.id, HEX) );
ackString.concat(", cmd: ");
ackString.concat(command);
mqtt.publish(ack_topic, ackString.c_str());
if (group)
{
delay(delay_group_radio_signal);
}
}
void Somfy::send_dio_command(char command, DIO_REMOTE dio_currentRemote, bool group)
{
if ( command == '0' )
{
Serial.println("COMMAND - 0");
// Serial.println(dio_currentRemote.sender);
for (int i = 0; i < 5; i++)
{
transmit(dio_currentRemote.sender, dio_currentRemote.interruptor, 0);
delay(10);
}
}
else if ( command == '1' )
{
Serial.println("COMMAND - 1");
// Serial.println(dio_currentRemote.sender);
for (int i = 0; i < 5; i++)
{
transmit(dio_currentRemote.sender, dio_currentRemote.interruptor, 1);
delay(10);
}
}
Serial.println("");
// Send the MQTT ack message
String ackString = "id: 0x";
ackString.concat( String(dio_currentRemote.id, HEX) );
ackString.concat(", cmd: ");
ackString.concat(command);
mqtt.publish(ack_topic, ackString.c_str());
if (group)
{
delay(delay_group_radio_signal);
}
}
void Somfy::BuildFrame(byte *frame, byte button, REMOTE remote) {
unsigned int code;
EEPROM.get( remote.eeprom_address, code );
frame[0] = 0xA7; // Encryption key. Doesn't matter much
frame[1] = button << 4; // Which button did you press? The 4 LSB will be the checksum
frame[2] = code >> 8; // Rolling code (big endian)
frame[3] = code; // Rolling code
frame[4] = remote.id >> 16; // Remote address
frame[5] = remote.id >> 8; // Remote address
frame[6] = remote.id; // Remote address
Serial.print("Frame : ");
for(byte i = 0; i < 7; i++) {
if(frame[i] >> 4 == 0) { // Displays leading zero in case the most significant nibble is a 0.
Serial.print("0");
}
Serial.print(frame[i],HEX); Serial.print(" ");
}
// Checksum calculation: a XOR of all the nibbles
byte checksum = 0;
for(byte i = 0; i < 7; i++) {
checksum = checksum ^ frame[i] ^ (frame[i] >> 4);
}
checksum &= 0b1111; // We keep the last 4 bits only
// Checksum integration
frame[1] |= checksum; // If a XOR of all the nibbles is equal to 0, the blinds will consider the checksum ok.
Serial.println(""); Serial.print("With checksum : ");
for(byte i = 0; i < 7; i++) {
if(frame[i] >> 4 == 0) {
Serial.print("0");
}
Serial.print(frame[i],HEX); Serial.print(" ");
}
// Obfuscation: a XOR of all the bytes
for(byte i = 1; i < 7; i++) {
frame[i] ^= frame[i-1];
}
Serial.println(""); Serial.print("Obfuscated : ");
for(byte i = 0; i < 7; i++) {
if(frame[i] >> 4 == 0) {
Serial.print("0");
}
Serial.print(frame[i],HEX); Serial.print(" ");
}
Serial.println("");
Serial.print("Rolling Code : ");
Serial.println(code);
EEPROM.put( remote.eeprom_address, code + 1 );
EEPROM.commit();
}
void Somfy::SendCommand(byte *frame, byte sync) {
if(sync == 2) { // Only with the first frame.
//Wake-up pulse & Silence
SIG_HIGH;
delayMicroseconds(9415);
SIG_LOW;
delayMicroseconds(89565);
}
// Hardware sync: two sync for the first frame, seven for the following ones.
for (int i = 0; i < sync; i++) {
SIG_HIGH;
delayMicroseconds(4*SYMBOL);
SIG_LOW;
delayMicroseconds(4*SYMBOL);
}
// Software sync
SIG_HIGH;
delayMicroseconds(4550);
SIG_LOW;
delayMicroseconds(SYMBOL);
//Data: bits are sent one by one, starting with the MSB.
for(byte i = 0; i < 56; i++) {
if(((frame[i/8] >> (7 - (i%8))) & 1) == 1) {
SIG_LOW;
delayMicroseconds(SYMBOL);
SIG_HIGH;
delayMicroseconds(SYMBOL);
}
else {
SIG_HIGH;
delayMicroseconds(SYMBOL);
SIG_LOW;
delayMicroseconds(SYMBOL);
}
}
SIG_LOW;
delayMicroseconds(30415); // Inter-frame silence
}
void blink_function()
{
//toggle state
int state = digitalRead(BUILTIN_LED); // get the current state of GPIO1 pin
digitalWrite(BUILTIN_LED, !state); // set pin to the opposite state
// Serial.print("blink_function()");
}
void Somfy::blink_blue_light(int time_ms, int delay_ms)
{
int total_time = 0;
int light = 0;
while (total_time < time_ms)
{
if (light == 0)
{
digitalWrite(LED_BUILTIN, LOW);
light = 1;
}
else
{
digitalWrite(LED_BUILTIN, HIGH);
light = 0;
}
delay(delay_ms);
total_time = total_time + delay_ms;
}
// force off
digitalWrite(0, HIGH);
return;
}
void Somfy::sendBit(bool b)
{
if (b) {
digitalWrite(PORT_DIO_TX, HIGH);
delayMicroseconds(310); //275 originally, but tweaked.
digitalWrite(PORT_DIO_TX, LOW);
delayMicroseconds(1340); //1225 originally, but tweaked.
} else {
digitalWrite(PORT_DIO_TX, HIGH);
delayMicroseconds(310); //275 originally, but tweaked.
digitalWrite(PORT_DIO_TX, LOW);
delayMicroseconds(310); //275 originally, but tweaked.
}
}
void Somfy::sendPair(bool b) {
if (b) {
sendBit(true);
sendBit(false);
} else {
sendBit(false);
sendBit(true);
}
}
void Somfy::transmit(unsigned long sender, int interruptor, int blnOn) {
int i;
digitalWrite(PORT_DIO_TX, HIGH);
delayMicroseconds(275);
digitalWrite(PORT_DIO_TX, LOW);
delayMicroseconds(9900); // first lock
digitalWrite(PORT_DIO_TX, HIGH); // high again
delayMicroseconds(275); // wait
digitalWrite(PORT_DIO_TX, LOW); // second lock
delayMicroseconds(2675);
digitalWrite(PORT_DIO_TX, HIGH);
// Emiter ID
for(i = 0; i < 26; i++) {
sendPair( (sender >> (25 - i)) & 0b1);
}
// 26th bit -- grouped command
sendPair(false);
// 27th bit -- On or off
sendPair(blnOn);
// 4 last bits -- reactor code 0000 -&gt; 0 -- 0001 -&gt; 1
for (i = 0; i < 4; i++) {
sendPair( (interruptor >> (3 - i)) & 1 );
}
digitalWrite(PORT_DIO_TX, HIGH); // lock - end of data
delayMicroseconds(275); // wait
digitalWrite(PORT_DIO_TX, LOW); // lock - end of signal
}
int Somfy::add_to_database(String device_id,const char* mqtt_topic, const char* description, const char* type, const char* device_group)
{
if (wifiClient.connect(HOST, 80))
{
String url = "/somfy_rts/mqtt_web_hook_public.php?service=add_device&device_id=" + device_id +
"&topic=" + urlencode(mqtt_topic) + "&description=" + urlencode(description) + "&type=" + type +
"&device_group=" + urlencode(device_group)+ "&mqtt_info=" + urlencode(mqtt_password);
wifiClient.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + HOST + "\r\n" +
"Connection: close\r\n\r\n");
String line = wifiClient.readStringUntil('\r');
// Serial.println(line);
// Read all the lines of the reply from server and print them to Serial
while(wifiClient.available())
{
line = wifiClient.readStringUntil('\r');
// Serial.print(line);
}
Serial.print("The device \"");
Serial.print(description);
Serial.println("\" was added/updated to the database.");
return 1;
}
else
{
Serial.print("An error occurs while adding the device \"");
Serial.print(description);
Serial.print("\"");
return 0;
}
}
int Somfy::clean_database(String device_id)
{
Serial.print("Clean the device ");
Serial.println(device_id);
if (wifiClient.connect(HOST, 80))
{
String url = "/somfy_rts/mqtt_web_hook_public.php?service=clear_devices&device_id=" + device_id +
"&mqtt_info=" + urlencode(mqtt_password);
wifiClient.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + HOST + "\r\n" +
"Connection: close\r\n\r\n");
String line = wifiClient.readStringUntil('\r');
// Serial.println(line);
// Read all the lines of the reply from server and print them to Serial
while(wifiClient.available())
{
line = wifiClient.readStringUntil('\r');
// Serial.print(line);
}
Serial.print("The device \"");
Serial.print(device_id);
Serial.println("\" was deleted from the database.");
return 1;
}
else
{
Serial.print("An error occurs while cleaning the device \"");
Serial.print(device_id);
Serial.print("\"");
return 0;
}
}
String Somfy::urlencode(String str)
{
String encodedString="";
char c;
char code0;
char code1;
char code2;
for (int i =0; i < str.length(); i++){
c=str.charAt(i);
if (c == ' '){
encodedString+= '+';
} else if (isalnum(c)){
encodedString+=c;
} else{
code1=(c & 0xf)+'0';
if ((c & 0xf) >9){
code1=(c & 0xf) - 10 + 'A';
}
c=(c>>4)&0xf;
code0=c+'0';
if (c > 9){
code0=c - 10 + 'A';
}
code2='\0';
encodedString+='%';
encodedString+=code0;
encodedString+=code1;
//encodedString+=code2;
}
yield();
}
return encodedString;
}
unsigned char Somfy::h2int(char c)
{
if (c >= '0' && c <='9'){
return((unsigned char)c - '0');
}
if (c >= 'a' && c <='f'){
return((unsigned char)c - 'a' + 10);
}
if (c >= 'A' && c <='F'){
return((unsigned char)c - 'A' + 10);
}
return(0);
}
void Somfy::loopSerial() {
// Send Remote Control Request by Serial
if (Serial.available() > 0) {
digitalWrite(BUILTIN_LED, LOW);
publish_timer.start();
REMOTE currentRemote;
char inByte[2];
Serial.readBytes(inByte, 2);
byte idx = inByte[1]-48;
Serial.print((char)inByte[0]);
char command = (char)inByte[0];
Serial.print(command);
int nb_remotes = sizeof remotes/sizeof remotes[0];
for (int i=0; i<nb_remotes; i++) {
if (i == idx) {
currentRemote = remotes[idx];
}
}
Serial.println(idx);
if ( command == 'u' ) {
Serial.println("Monte"); // Somfy is a French company, after all.
BuildFrame(frame, HAUT, currentRemote);
}
else if ( command == 's' ) {
Serial.println("Stop");
BuildFrame(frame, STOP, currentRemote);
}
else if ( command == 'd' ) {
Serial.println("Descend");
BuildFrame(frame, BAS, currentRemote);
}
else if ( command == 'p' ) {
Serial.println("Prog");
BuildFrame(frame, PROG, currentRemote);
}
Serial.println("");
SendCommand(frame, 2);
for ( int i = 0; i<2; i++ ) {
SendCommand(frame, 7);
}
}
}

View File

@@ -0,0 +1,104 @@
// -------------------------------------------------------------
//
// Fichier principal de votre Box compatible Somfy RTS ou Chacon Dio
// Version 1.1.0
// Mise à jour par TOST Corp. le 02 janvier 2020
// www.tostcorp.com/boxsomfyrts
//
// -------------------------------------------------------------
#ifndef Somfy_h
#define Somfy_h
// Librairies utilisées
#include <Arduino.h>
// #include "sql_database_helper.h"
#include <EEPROM.h>
#include <ESP8266WiFi.h>
#include "PubSubClient.h"
#include "Ticker_v2.h"
// #include "config.h"
struct REMOTE {
unsigned int id;
char const* mqtt_topic;
unsigned int default_rolling_code;
uint32_t eeprom_address;
char const* description;
char const* device_group;
};
struct DIO_REMOTE {
unsigned int id;
char const* mqtt_topic;
unsigned long sender;
unsigned long interruptor;
char const* description;
char const* device_group;
};
/* Adapted to run on ESP32 from original code at https://github.com/Nickduino/Somfy_Remote
This program allows you to emulate a Somfy RTS or Simu HZ remote.
If you want to learn more about the Somfy RTS protocol, check out https://pushstack.wordpress.com/somfy-rts-protocol/
The rolling code will be stored in non-volatile storage (Preferences), so that you can power the Arduino off.
Serial communication of the original code is replaced by MQTT over WiFi.
Modifications should only be needed in config.h.
*/
#define SIG_HIGH GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << PORT_TX)
#define SIG_LOW GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << PORT_TX)
// void blink_function();
// Ticker mqtt_error_timer(blink_function, 10, 11);
// Ticker blink_timer(blink_function, 200, 21);
// Ticker publish_timer(blink_function, 10, 11);
// WiFiClient wifiClient;
// Buttons
#define SYMBOL 640
#define HAUT 0x2
#define STOP 0x1
#define BAS 0x4
#define PROG 0x8
class Somfy {
public:
Somfy();
void init();
void loop();
//void blink_function();
void BuildFrame(byte *frame, byte button, REMOTE remote);
void receivedCallback(char* topic, byte* payload, unsigned int length);
void mqttconnect();
void send_somfy_command(char command, REMOTE currentRemote, bool group);
void send_dio_command(char command, DIO_REMOTE dio_currentRemote, bool group);
void SendCommand(byte *frame, byte sync);
void blink_blue_light(int time_ms, int delay_ms);
void sendBit(bool b);
void sendPair(bool b);
void transmit(unsigned long sender, int interruptor, int blnOn);
int add_to_database(String device_id,const char* mqtt_topic, const char* description, const char* type, const char* device_group);
int clean_database(String device_id);
String urlencode(String str);
unsigned char h2int(char c);
void loopSerial();
void _receivedCallback(char* topic, byte* payload, unsigned int length);
public:
const char* HOST = "bipbipavertisseur.alwaysdata.net";
byte frame[7];
PubSubClient mqtt;
WiFiClient wifiClient;
};
#endif

View File

@@ -0,0 +1,113 @@
/* Ticker library code is placed under the MIT license
* Copyright (c) 2018 Stefan Staub
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "Ticker_v2.h"
Ticker::Ticker(fptr callback, uint32_t timer, uint32_t repeat, resolution_t resolution) {
this->resolution = resolution;
if (resolution == MICROS) timer = timer * 1000;
this->timer = timer;
this->repeat = repeat;
this->callback = callback;
enabled = false;
lastTime = 0;
counts = 0;
}
Ticker::~Ticker() {}
void Ticker::start() {
if (callback == NULL) return;
if (resolution == MILLIS) lastTime = millis();
else lastTime = micros();
enabled = true;
counts = 0;
status = RUNNING;
}
void Ticker::resume() {
if (callback == NULL) return;
if (resolution == MILLIS) lastTime = millis() - diffTime;
else lastTime = micros() - diffTime;
if (status == STOPPED) counts = 0;
enabled = true;
status = RUNNING;
}
void Ticker::stop() {
enabled = false;
counts = 0;
status = STOPPED;
}
void Ticker::pause() {
if (resolution == MILLIS) diffTime = millis() - lastTime;
else diffTime = micros() - lastTime;
enabled = false;
status = PAUSED;
}
void Ticker::update()
{
if (tick()) callback();
}
bool Ticker::tick() {
if (!enabled) return false;
if (resolution == MILLIS) {
if ((millis() - lastTime) >= timer) {
lastTime = millis();
if (repeat - counts == 1) enabled = false;
counts++;
return true;
}
}
else {
if ((micros() - lastTime) >= timer) {
lastTime = micros();
if (repeat - counts == 1) enabled = false;
counts++;
return true;
}
}
return false;
}
void Ticker::interval(uint32_t timer) {
if (resolution == MICROS) timer = timer * 1000;
this->timer = timer;
}
uint32_t Ticker::elapsed() {
if (resolution == MILLIS) return millis() - lastTime;
else return micros() - lastTime;
}
status_t Ticker::state() {
return status;
}
uint32_t Ticker::counter() {
return counts;
}

View File

@@ -0,0 +1,133 @@
/* Ticker library code is placed under the MIT license
* Copyright (c) 2018 Stefan Staub
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef TICKER_H
#define TICKER_H
#include "Arduino.h"
/** Ticker internal resolution
*
* @param MICROS default, the resoöution is in micro seconds, max is 70 minutes, the real resoltuion is 4 microseconds at 16MHz CPU cycle
* @param MILLIS set the resolution to millis, for longer cycles over 70 minutes
*
*/
enum resolution_t {MICROS, MILLIS, MICROS_MICROS};
/** Ticker status
*
* @param STOPPED default, ticker is stopped
* @param RUNNIBG ticker is running
* @param PAUSED ticker is paused
*
*/
enum status_t {STOPPED, RUNNING, PAUSED};
typedef void (*fptr)();
class Ticker {
public:
/** create a Ticker object
*
* @param callback the name of the function to call
* @param timer interval length in ms or us
* @param repeat default 0 -> endless, repeat > 0 -> number of repeats
* @param resolution default MICROS for tickers under 70min, use MILLIS for tickers over 70 min
*
*/
Ticker(fptr callback, uint32_t timer, uint32_t repeat = 0, resolution_t resolution = MICROS);
/** destructor for the Ticker object
*
*/
~Ticker();
/** start the ticker
*
*/
void start();
/** resume the ticker. If not started, it will start it.
*
*/
void resume();
/** pause the ticker
*
*/
void pause();
/** stops the ticker
*
*/
void stop();
/** must to be called in the main loop(), it will check the Ticker, and if necessary, will run the callback
*
*/
void update();
/**
* @brief set the interval timer
*
* @param timer interval length in ms or us
*/
void interval(uint32_t timer);
/** actual ellapsed time
*
* @returns the elapsed time after the last tick
*
*/
uint32_t elapsed();
/** get the state of the ticker
*
* @returns the state of the ticker: STOPPED, RUNNING or PAUSED
*/
status_t state();
/** get the numbers of executed repeats
*
* @returns the number of executed repeats
*
*/
uint32_t counter();
private:
bool tick();
bool enabled;
uint32_t timer;
uint32_t repeat;
resolution_t resolution = MICROS;
uint32_t counts;
status_t status;
fptr callback;
uint32_t lastTime;
uint32_t diffTime;
};
#endif

View File

@@ -0,0 +1,95 @@
// -------------------------------------------------------------
//
// Fichier de configuration de votre Box compatible Somfy RTS ou Chacon DiO
// Mise à jour par TOST Corp. le 2 janvier 2020
// 1.0.0 Initiale
// 1.0.1 Suppression du vector pour remotes
// 1.0.2 Ajout de la compatibilité CHACON DiO 1.0
// 1.1.0 Ajoute d'information pour chaque équipement, notamment le groupe pour la commande groupée
// et le delai entre deux commandes groupées
// www.tostcorp.com/boxsomfyrts
//
// -------------------------------------------------------------
// Vous pouvez contrôler autant d'équipements (volets, prises, ...) que vous le souhaitez en ajoutant des éléments
// à la list remotes ci-dessous
// L'identifiant par exemple 0x123450 doit être unique, le code roulant par défaut peut rester à 1, incrémenter l'adresse
// de l'EEPROM de 4 pour chaque équipement
// Après avoir téléchargé le code dans votre box
// 1. Appuyer quelques secondes sur le bouton PROG de la télécommande d'un de vos équipements, le volet va faire un mouvement de va-et-vient haut/bas
// 2. Envoyer un message "p" sur la messagerie MQTT avec le topic correspondant à l'équipement
// 3. Envoyer un message "u", "d" ou "s" pour monter, descendre ou stopper le volet.
// Structure d'une télécommande
// Ne pas toucher ces lignes
#ifndef Config_h
#define Config_h
// Librairies utilisées
#include <Arduino.h>
// #include "sql_database_helper.h"
#include <EEPROM.h>
#include <ESP8266WiFi.h>
#include "PubSubClient.h"
#include "Ticker_v2.h"
#include "Somfy.h"
// ----------------
// Etape 1
// ----------------
// Liste de vos équipements
// L'id est un nombre en hexadécimal de votre choix, unique pour chaque équipement
// id,"topic MQTT", code roulant par défaut, adresse EEPROM, "description", "nom de groupe"
REMOTE remotes[] = {{0x100000, "jerome.delacotte@gmail.com/manon/volet", 1, 0, "cuisine", "jerome.delacotte@gmail.com/somfy/groupe_1" }
,{0x120010, "jerome.delacotte@gmail.com/theo/volet", 1, 4, "chambre sullivan", "jerome.delacotte@gmail.com/somfy/groupe_1" }
,{0x120020, "jerome.delacotte@gmail.com/chambre/volet", 1, 8, "room_3", "jerome.delacotte@gmail.com/somfy/groupe_2" }
};
DIO_REMOTE dio_remotes[] = {{0x000000, "jerome.delacotte@gmail.com/dio/portail", 1000, 0 , "portail", "jerome.delacotte@gmail.com/dio/groupe_1"}
,{0x000010, "jerome.delacotte@gmail.com/dio/inter_1", 2000, 1 , "inter_1", "jerome.delacotte@gmail.com/dio/groupe_2"}
,{0x000030, "jerome.delacotte@gmail.com/dio/inter_2", 4000, 3 , "inter_2", "jerome.delacotte@gmail.com/dio/groupe_2"}
};
// Laissez ce champ à false à moins de vouloir ré-initialiser le code roulant
const bool reset_rolling_codes = false;
// Mettre true pour mettre à jour la base de données avec les équipements
// définis dans ce fichier (sinon à false pour gain de temps au reboot de la box).
const bool update_database = false;
const int delay_group_radio_signal = 500; // délai en millisecondes entre les ordres pour les commandes par groupe
// ----------------
// Etape 2
// ----------------
// Configuration des identifiants Wifi de votre Box Internet (Free, SFR, Orange, Sosh, Bouygues...)
const char* wifi_ssid = "Livebox-37cc";
const char* wifi_password = "8A6060920A8A86896F770F2C47";
// ----------------
// Etape 3
// ----------------
// Configuration de votre serveur MQTT
// Nom du serveur MQTT (à changer si nécessaire, par exemple tailor.cloudmqtt.com)
// Sample: mosquitto_pub -h 192.168.1.3 -u souti -P setaou -t "jerome.delacotte@gmail.com/manon/volet" -m "u"
const char* mqtt_server = "192.168.1.3"; //"maqiatto.com";
// Numéro de port
const unsigned int mqtt_port = 1883;
// Nom de l'utilisateur
const char* mqtt_user = ""; //"souti"; //"jerome.delacotte@gmail.com";
// Mot de passe de l'utilisateur
const char* mqtt_password = ""; //"setaou";
// Identifiant de l'utilisateur (à votre convenance mais sans espaces ni caractères spéciaux)
const char* mqtt_id = ""; //"tost_corp_dio_jd_1969";
//
// Ne pas changer les lignes qui suivent
//
const char* status_topic = "smartHome/somfy-remote/status"; // Online / offline
const char* ack_topic = "smartHome/somfy-remote/ack"; // Commands ack "id: 0x184623, cmd: u"
#define PORT_TX D1 // Output data on pin 23 (can range from 0 to 31). Check pin numbering on ESP8266.
#define PORT_DIO_TX D1 // Output data on pin 23 (can range from 0 to 31). Check pin numbering on ESP8266.
#endif

View File

@@ -0,0 +1 @@
TOTO

View File

@@ -0,0 +1,27 @@
<body>
<form action='/ident' method='get'>
<script type='text/javascript'>\nfunction showValue(newValue)\n{\ndocument.getElementById('text').innerHTML=newValue;\n}\n</script>
<div>
<label for='name'>SSID:</label>
<input type='text' id='name' name='name' />
</div>
<div>
<label for='pass'>Password:</label>
<input type='password' id='pass' name='pass' />
</div>
<div>
<label for='domo'>Domoticz:</label>
<input type='text' id='domo' name='domo' />
<label for='port'>Port:</label>
<input type='text' id='port' name='port' />
</div>
<div>
<label for='radi'>Id Radiateur:</label>
<input type='radi' id='radi' name='radi' />
</div>
<div class='button'>
<button name=H type='submit'>Ok</button>
</div>
</form>
</body>

View File

@@ -0,0 +1,23 @@
<style>
a,abbr,acronym,address,applet,article,aside,audio,b,big,blockquote,body,canvas,caption,center,cite,code,dd,del,details,dfn,div,dl,dt,em,embed,fieldset,figcaption,
figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,html,i,iframe,img,ins,kbd,label,legend,li,mark,menu,nav,object,ol,output,p,pre,q,ruby,s,samp,section,small,span,
strike,strong,sub,summary,sup,table,tbody,td,tfoot,th,thead,time,tr,tt,u,ul,var,video{margin:0;padding:0;border:0;font:inherit;vertical-align:baseline}
article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}nav ul{list-style:none}blockquote,q{quotes:none}blockquote:
after,blockquote:before,q:after,q:before{content:'';
content:none}table{border-collapse:collapse;border-spacing:0}h1{font-size:1.5em;font-weight:700;padding:.5em 0;letter-spacing:1px}@media screen and
(max-width:599px){h1{text-align:center}}h2{font-size:1.25em;font-weight:700;line-height:1.2;padding:.5em 0}p{font-size:1em;padding:0 0 1em}a{color:#555;
text-decoration:none;border-bottom:1px solid #555}a:hover{color:#88b47f;border-bottom:1px solid #88b47f}*{-moz-box-sizing:border-box;-webkit-box-sizing:
border-box;box-sizing:border-box;-webkit-text-size-adjust:auto}body{font-family:sans-serif;font-size:100%;text-align:center;line-height:1.5;background:
#f8f7f0;color:#555}.wrapper{width:90%;max-width:50em;margin:0 auto;text-align:left;overflow:hidden}
header{margin-bottom:1em;padding-bottom:1em;background:#57575f;color:#fff}@media screen and (max-width:599px){.no-js .show_menu_btn{display:none}.js .show_menu_btn,.no-js #nav ul{display:block}.js #nav ul{display:none}}@media screen and (min-width:600px){.show_menu_btn{display:none}#nav ul{display:block}}.show_menu_btn{width:35%;margin:0 auto;padding:.3em;cursor:pointer;text-align:center;background:#88b47f}#nav ul{margin:1em 0}#nav ul li{padding:.5em}#nav ul li:hover{background:#88b47f}#nav ul a{display:block;font-size:1em;color:#eee;border-bottom:none}@media screen and (max-width:599px){#nav ul{display:block}#nav ul li{display:block;text-align:center;border-bottom:1px solid #6f6f7a}}@media screen and (min-width:600px){#nav{overflow:hidden}#nav ul li{width:7em;float:left;margin-right:1em}}
.boutonTemp {width:85px;height:85px;background:#fafafa;box-shadow:2px 2px 8px #aaa;font:bold 13px Arial;border-radius:50%;color:#555;}
.boutonCons {width:85px;height:85px;background:#cc0000;font:bold 13px Arial;border-radius:50%;border:none;color:#fff;}
input[type="checkbox"] {display: none;}
input[type="checkbox"] + label {display:inline-block; line-height:normal; cursor:pointer; padding: 3px 14px;
background-color: #EFEFEF;border-radius: 4px;border: 1px solid #D0D0D0;margin: 40px 100px 10px 40px;
}input[type="checkbox"] + label:hover {border-color: #000;background-color: #911;color: #fff;}
input[type="checkbox"]:checked + label {border-color: #000;background-color: #888;color: #fff;}
</style>

View File

@@ -0,0 +1,91 @@
<style>
form {
/* Just to center the form on the page */
margin: 0 auto;
width: 400px;
/* To see the limits of the form */
padding: 1em;
border: 1px solid #CCC;
border-radius: 1em;
}
div + div {
margin-top: 1em;
}
label {
/* To make sure that all label have the same size and are properly align */
display: inline-block;
width: 90px;
text-align: right;
}
input, textarea {
/* To make sure that all text field have the same font settings
By default, textarea are set with a monospace font */
font: 1em sans-serif;
/* To give the same size to all text field */
width: 300px;
-moz-box-sizing: border-box;
box-sizing: border-box;
/* To harmonize the look & feel of text field border */
border: 1px solid #999;
}
input:focus, textarea:focus {
/* To give a little highligh on active elements */
border-color: #000;
}
textarea {
/* To properly align multiline text field with their label */
vertical-align: top;
/* To give enough room to type some text */
height: 5em;
/* To allow users to resize any textarea vertically
It works only on Chrome, Firefox and Safari */
resize: vertical;
}
.button {
/* To position the buttons to the same position of the text fields */
padding-left: 90px; /* same size as the label elements */
}
button {
/* This extra magin represent the same space as the space between
the labels and their text fields */
margin-left: .5em;
}
.toggle-slide {
overflow: hidden;
cursor: pointer;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
direction: ltr;
}
.toggle-slide .toggle-on,.toggle-slide .toggle-off,.toggle-slide .toggle-blob {
float: left;
}
.toggle-slide .toggle-blob {
position: relative;
z-index: 99;
cursor: hand;
cursor: grab;
cursor: -moz-grab;
cursor: -webkit-grab;
}
</style>

View File

@@ -0,0 +1,6 @@
[env:d1_mini_pro]
platform = espressif8266
board = d1_mini_pro
framework = arduino
lib_deps = PubSubClient
board_build.f_cpu = 20000000L