My environment
[env:heltec-display] ; Heltec ESP32 Board with SSD1306 display
platform = ${com.esp32_platform}
board = heltec_wifi_lora_32_V2
build_type = debug
monitor_filters = esp32_exception_decoder
board_build.partitions = min_spiffs.csv
extra_scripts = pre:scripts/omg_firmware_version.py
lib_deps =
${com-esp.lib_deps}
${libraries.wifimanager32}
${libraries.heltec}
; ${libraries.m5stickcp}
build_flags =
${com-esp.build_flags}
${test_env.build_flags}
; *** OpenMQTTGateway Config ***
'-UZmqttDiscovery' ; disables MQTT Discovery
'-DvalueAsATopic=true'
'-DLOG_LEVEL=LOG_LEVEL_TRACE'
; *** OpenMQTTGateway Modules ***
'-DZboardHELTEC="HELTEC"'
; *** Heltec Board Options ***
'-DDEBUG_OLEDDISPLAY(...)=Serial.printf( __VA_ARGS__ )'
'-DLOG_TO_LCD=true' ; Enable log to LCD
'-DLED_ERROR=2'
'-DONBOARD_LED=25' ; Onboard LED is GPIO 25 on the Heltec Board
monitor_port = /dev/cu.SLAB_USBtoUART
monitor_speed = 921600
upload_port = /dev/cu.SLAB_USBtoUART
upload_speed = 921600
1 - Set default LCD log level to WARNING
2 - Implemented a macro based displayPrint function that will be usable across different displays
- Added logo display when idle
- Fixed log-lcd mqtt function
- Enable OLED Display on Heltec Boards
10278 lines
308 KiB
C++
10278 lines
308 KiB
C++
# 1 "/var/folders/nk/2b522cbn5pdfsm1_n0zm50680000gp/T/tmp3fm37ml6"
|
|
#include <Arduino.h>
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/main.ino"
|
|
# 28 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/main.ino"
|
|
#include "User_config.h"
|
|
|
|
|
|
#if defined(ZgatewayRF) || defined(ZgatewayIR) || defined(ZgatewaySRFB) || defined(ZgatewayWeatherStation)
|
|
|
|
struct ReceivedSignal {
|
|
SIGNAL_SIZE_UL_ULL value;
|
|
uint32_t time;
|
|
};
|
|
# if defined(ESP8266) || defined(ESP32) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__)
|
|
ReceivedSignal receivedSignal[] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}};
|
|
# else
|
|
ReceivedSignal receivedSignal[] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}};
|
|
# endif
|
|
#define struct_size (sizeof(receivedSignal) / sizeof(ReceivedSignal))
|
|
#endif
|
|
|
|
#if defined(ESP8266) || defined(ESP32) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__)
|
|
|
|
unsigned long timer_sys_measures = 0;
|
|
#define ARDUINOJSON_USE_LONG_LONG 1
|
|
#define ARDUINOJSON_ENABLE_STD_STRING 1
|
|
#endif
|
|
|
|
#include <ArduinoJson.h>
|
|
#include <ArduinoLog.h>
|
|
#include <PubSubClient.h>
|
|
|
|
#include <string>
|
|
|
|
StaticJsonDocument<JSON_MSG_BUFFER> modulesBuffer;
|
|
JsonArray modules = modulesBuffer.to<JsonArray>();
|
|
|
|
#ifndef ZgatewayGFSunInverter
|
|
|
|
|
|
|
|
struct GfSun2000Data {};
|
|
#endif
|
|
|
|
|
|
#if defined(ZgatewayRF) || defined(ZgatewayRF2) || defined(ZgatewayPilight) || defined(ZactuatorSomfy) || defined(ZgatewayRTL_433)
|
|
# include "config_RF.h"
|
|
#endif
|
|
#ifdef ZgatewayWeatherStation
|
|
# include "config_WeatherStation.h"
|
|
#endif
|
|
#ifdef ZgatewayGFSunInverter
|
|
# include "config_GFSunInverter.h"
|
|
#endif
|
|
#ifdef ZgatewayLORA
|
|
# include "config_LORA.h"
|
|
#endif
|
|
#ifdef ZgatewaySRFB
|
|
# include "config_SRFB.h"
|
|
#endif
|
|
#ifdef ZgatewayBT
|
|
# include "config_BT.h"
|
|
#endif
|
|
#ifdef ZgatewayIR
|
|
# include "config_IR.h"
|
|
#endif
|
|
#ifdef Zgateway2G
|
|
# include "config_2G.h"
|
|
#endif
|
|
#ifdef ZactuatorONOFF
|
|
# include "config_ONOFF.h"
|
|
#endif
|
|
#ifdef ZsensorINA226
|
|
# include "config_INA226.h"
|
|
#endif
|
|
#ifdef ZsensorHCSR501
|
|
# include "config_HCSR501.h"
|
|
#endif
|
|
#ifdef ZsensorADC
|
|
# include "config_ADC.h"
|
|
#endif
|
|
#ifdef ZsensorBH1750
|
|
# include "config_BH1750.h"
|
|
#endif
|
|
#ifdef ZsensorTSL2561
|
|
# include "config_TSL2561.h"
|
|
#endif
|
|
#ifdef ZsensorBME280
|
|
# include "config_BME280.h"
|
|
#endif
|
|
#ifdef ZsensorHTU21
|
|
# include "config_HTU21.h"
|
|
#endif
|
|
#ifdef ZsensorAHTx0
|
|
# include "config_AHTx0.h"
|
|
#endif
|
|
#ifdef ZsensorHCSR04
|
|
# include "config_HCSR04.h"
|
|
#endif
|
|
#ifdef ZsensorDHT
|
|
# include "config_DHT.h"
|
|
#endif
|
|
#ifdef ZsensorSHTC3
|
|
# include "config_SHTC3.h"
|
|
#endif
|
|
#ifdef ZsensorDS1820
|
|
# include "config_DS1820.h"
|
|
#endif
|
|
#ifdef ZgatewayRFM69
|
|
# include "config_RFM69.h"
|
|
#endif
|
|
#ifdef ZsensorGPIOInput
|
|
# include "config_GPIOInput.h"
|
|
#endif
|
|
#ifdef ZsensorGPIOKeyCode
|
|
# include "config_GPIOKeyCode.h"
|
|
#endif
|
|
#ifdef ZmqttDiscovery
|
|
# include "config_mqttDiscovery.h"
|
|
#endif
|
|
#ifdef ZactuatorFASTLED
|
|
# include "config_FASTLED.h"
|
|
#endif
|
|
#ifdef ZactuatorPWM
|
|
# include "config_PWM.h"
|
|
#endif
|
|
#ifdef ZactuatorSomfy
|
|
# include "config_Somfy.h"
|
|
#endif
|
|
#if defined(ZboardM5STICKC) || defined(ZboardM5STICKCP) || defined(ZboardM5STACK) || defined(ZboardM5TOUGH)
|
|
# include "config_M5.h"
|
|
#endif
|
|
#if defined(ZboardHELTEC)
|
|
# include "config_HELTEC.h"
|
|
#endif
|
|
#if defined(ZgatewayRS232)
|
|
# include "config_RS232.h"
|
|
#endif
|
|
|
|
|
|
void setupTLS(bool self_signed = false, uint8_t index = 0);
|
|
|
|
|
|
void callback(char* topic, byte* payload, unsigned int length);
|
|
|
|
char mqtt_user[parameters_size + 1] = MQTT_USER;
|
|
char mqtt_pass[parameters_size + 1] = MQTT_PASS;
|
|
char mqtt_server[parameters_size + 1] = MQTT_SERVER;
|
|
char mqtt_port[6] = MQTT_PORT;
|
|
char mqtt_topic[parameters_size + 1] = Base_Topic;
|
|
char gateway_name[parameters_size + 1] = Gateway_Name;
|
|
#ifdef USE_MAC_AS_GATEWAY_NAME
|
|
#undef WifiManager_ssid
|
|
#undef ota_hostname
|
|
#define MAC_NAME_MAX_LEN 30
|
|
char WifiManager_ssid[MAC_NAME_MAX_LEN];
|
|
char ota_hostname[MAC_NAME_MAX_LEN];
|
|
#endif
|
|
bool connectedOnce = false;
|
|
bool justReconnected = false;
|
|
int failure_number_ntwk = 0;
|
|
int failure_number_mqtt = 0;
|
|
#ifdef ZmqttDiscovery
|
|
bool disc = true;
|
|
#endif
|
|
unsigned long timer_led_measures = 0;
|
|
static void* eClient = nullptr;
|
|
#if defined(ESP8266) || defined(ESP32)
|
|
static bool mqtt_secure = MQTT_SECURE_DEFAULT;
|
|
static uint8_t mqtt_ss_index = MQTT_SECURE_SELF_SIGNED_INDEX_DEFAULT;
|
|
static String mqtt_cert = "";
|
|
static String ota_server_cert = "";
|
|
#endif
|
|
|
|
#ifdef ESP32
|
|
# include <ArduinoOTA.h>
|
|
# include <FS.h>
|
|
# include <SPIFFS.h>
|
|
# include <nvs.h>
|
|
# include <nvs_flash.h>
|
|
|
|
# ifdef ESP32_ETHERNET
|
|
# include <ETH.h>
|
|
void WiFiEvent(WiFiEvent_t event);
|
|
static bool esp32EthConnected = false;
|
|
# endif
|
|
|
|
# include <WiFiClientSecure.h>
|
|
# include <WiFiMulti.h>
|
|
WiFiMulti wifiMulti;
|
|
# include <Preferences.h>
|
|
# include <WiFiManager.h>
|
|
Preferences preferences;
|
|
# ifdef MDNS_SD
|
|
# include <ESPmDNS.h>
|
|
# endif
|
|
|
|
#elif defined(ESP8266)
|
|
# include <ArduinoOTA.h>
|
|
# include <DNSServer.h>
|
|
# include <ESP8266WebServer.h>
|
|
# include <ESP8266WiFi.h>
|
|
# include <ESP8266WiFiMulti.h>
|
|
# include <FS.h>
|
|
# include <WiFiManager.h>
|
|
X509List caCert;
|
|
# if MQTT_SECURE_SELF_SIGNED_CLIENT
|
|
X509List* pClCert = nullptr;
|
|
PrivateKey* pClKey = nullptr;
|
|
# endif
|
|
ESP8266WiFiMulti wifiMulti;
|
|
# ifdef MDNS_SD
|
|
# include <ESP8266mDNS.h>
|
|
# endif
|
|
|
|
#else
|
|
# include <Ethernet.h>
|
|
#endif
|
|
|
|
#define convertTemp_CtoF(c) ((c * 1.8) + 32)
|
|
#define convertTemp_FtoC(f) ((f - 32) * 5 / 9)
|
|
|
|
|
|
PubSubClient client;
|
|
void revert_hex_data(const char* in, char* out, int l);
|
|
char* ip2CharArray(IPAddress ip);
|
|
bool to_bool(String const& s);
|
|
void pub(const char* topicori, const char* payload, bool retainFlag);
|
|
void pub(const char* topicori, JsonObject& data);
|
|
void pub(const char* topicori, const char* payload);
|
|
void pub_custom_topic(const char* topic, JsonObject& data, boolean retain);
|
|
void pubMQTT(const char* topic, const char* payload);
|
|
void pubMQTT(const char* topic, const char* payload, bool retainFlag);
|
|
void pubMQTT(String topic, const char* payload);
|
|
void pubMQTT(const char* topic, unsigned long payload);
|
|
void pubMQTT(const char* topic, unsigned long long payload);
|
|
void pubMQTT(const char* topic, String payload);
|
|
void pubMQTT(String topic, String payload);
|
|
void pubMQTT(String topic, int payload);
|
|
void pubMQTT(String topic, unsigned long long payload);
|
|
void pubMQTT(String topic, float payload);
|
|
void pubMQTT(const char* topic, float payload);
|
|
void pubMQTT(const char* topic, int payload);
|
|
void pubMQTT(const char* topic, unsigned int payload);
|
|
void pubMQTT(const char* topic, long payload);
|
|
void pubMQTT(const char* topic, double payload);
|
|
void pubMQTT(String topic, unsigned long payload);
|
|
bool cmpToMainTopic(const char* topicOri, const char* toAdd);
|
|
void connectMQTT();
|
|
void setup();
|
|
bool wifi_reconnect_bypass();
|
|
void setOTA();
|
|
void setupTLS(bool self_signed, uint8_t index);
|
|
void setup_wifi();
|
|
void saveConfigCallback();
|
|
void checkButton();
|
|
void checkButton();
|
|
void eraseAndRestart();
|
|
void saveMqttConfig();
|
|
void setup_wifimanager(bool reset_settings);
|
|
void setup_ethernet_esp32();
|
|
void setup_ethernet();
|
|
void connectMQTTmdns();
|
|
void loop();
|
|
unsigned long uptime();
|
|
void stateMeasures();
|
|
void storeSignalValue(SIGNAL_SIZE_UL_ULL MQTTvalue);
|
|
int getMin();
|
|
bool isAduplicateSignal(SIGNAL_SIZE_UL_ULL value);
|
|
void receivingMQTT(char* topicOri, char* datacallback);
|
|
void MQTTHttpsFWUpdate(char* topicOri, JsonObject& HttpsFwUpdateData);
|
|
void MQTTtoSYS(char* topicOri, JsonObject& SYSdata);
|
|
String toString(uint64_t input);
|
|
String toString(uint32_t input);
|
|
void watchdogReboot(byte reason);
|
|
void setupFASTLED();
|
|
int animation_step(int duration, int steps);
|
|
int animation_step_count(int duration, int steps);
|
|
void FASTLEDLoop();
|
|
boolean FASTLEDtoMQTT();
|
|
void MQTTtoFASTLED(char* topicOri, JsonObject& jsonData);
|
|
void MQTTtoFASTLED(char* topicOri, char* datacallback);
|
|
void Fire2012WithPalette();
|
|
void MQTTtoONOFF(char* topicOri, JsonObject& ONOFFdata);
|
|
void MQTTtoONOFF(char* topicOri, char* datacallback);
|
|
void ActuatorButtonTrigger();
|
|
void setupPWM();
|
|
static float perceptualToLinear(float perceptual, int channelIdx);
|
|
void PWMLoop();
|
|
boolean PWMtoMQTT();
|
|
void MQTTtoPWM(char* topicOri, JsonObject& jsonData);
|
|
void setupSomfy();
|
|
void MQTTtoSomfy(char* topicOri, JsonObject& jsonData);
|
|
void logToLCD(bool display);
|
|
void setupHELTEC();
|
|
void loopHELTEC();
|
|
void MQTTtoHELTEC(char* topicOri, JsonObject& HELTECdata);
|
|
void heltecPrint(char* line1, char* line2, char* line3);
|
|
void heltecPrint(char* line1, char* line2);
|
|
void heltecPrint(char* line1);
|
|
void logToLCD(bool display);
|
|
void setBrightness(int brightness);
|
|
void setupM5();
|
|
void sleepScreen();
|
|
void wakeScreen(int brightness);
|
|
void loopM5();
|
|
void MQTTtoM5(char* topicOri, JsonObject& M5data);
|
|
void displayIntro(int i, int X, int Y);
|
|
void drawLogo(int logoSize, int circle1X, int circle1Y, bool circle1, bool circle2, bool circle3, bool line1, bool line2, bool name);
|
|
void M5Print(char* line1, char* line2, char* line3);
|
|
void setup2G();
|
|
void setupGSM(bool deleteSMS);
|
|
void signalStrengthAnalysis();
|
|
bool _2GtoMQTT();
|
|
void MQTTto2G(char* topicOri, char* datacallback);
|
|
void MQTTto2G(char* topicOri, JsonObject& SMSdata);
|
|
void BTConfig_init();
|
|
void BTConfig_load();
|
|
JsonObject& getBTJsonObject(const char* json, bool haPresenceEnabled);
|
|
void pubBT(JsonObject& data);
|
|
void emptyBTQueue();
|
|
bool updateWorB(JsonObject& BTdata, bool isWhite);
|
|
void createOrUpdateDevice(const char* mac, uint8_t flags, int model, int mac_type);
|
|
void dumpDevices();
|
|
void strupp(char* beg);
|
|
void DT24Discovery(const char* mac, const char* sensorModel_id);
|
|
void LYWSD03MMCDiscovery(const char* mac, const char* sensorModel);
|
|
void MHO_C401Discovery(const char* mac, const char* sensorModel);
|
|
void HHCCJCY01HHCCDiscovery(const char* mac, const char* sensorModel);
|
|
void XMWSDJ04MMCDiscovery(const char* mac, const char* sensorModel);
|
|
void LYWSD03MMCDiscovery(const char* mac, const char* sensorModel);
|
|
void MHO_C401Discovery(const char* mac, const char* sensorModel);
|
|
void HHCCJCY01HHCCDiscovery(const char* mac, const char* sensorModel);
|
|
void DT24Discovery(const char* mac, const char* sensorModel_id);
|
|
void XMWSDJ04MMCDiscovery(const char* mac, const char* sensorModel_id);
|
|
void procBLETask(void* pvParameters);
|
|
void BLEscan();
|
|
void BLEconnect();
|
|
void stopProcessing();
|
|
void startProcessing();
|
|
void coreTask(void* pvParameters);
|
|
void lowPowerESP32();
|
|
void deepSleep(uint64_t time_in_us);
|
|
void changelowpowermode(int newLowPowerMode);
|
|
void setupBT();
|
|
bool BTtoMQTT();
|
|
void RemoveJsonPropertyIf(JsonObject& obj, const char* key, bool condition);
|
|
boolean valid_service_data(const char* data, int size);
|
|
void launchBTDiscovery();
|
|
void PublishDeviceData(JsonObject& BLEdata, bool processBLEData);
|
|
void process_bledata(JsonObject& BLEdata);
|
|
void hass_presence(JsonObject& HomePresence);
|
|
void BTforceScan();
|
|
void immediateBTAction(void* pvParameters);
|
|
void startBTActionTask();
|
|
void MQTTtoBTAction(JsonObject& BTdata);
|
|
void MQTTtoBT(char* topicOri, JsonObject& BTdata);
|
|
void GFSunInverterDataHandler(GfSun2000Data data);
|
|
void GFSunInverterErrorHandler(int errorId, char* errorMessage);
|
|
void setupGFSunInverter();
|
|
void ZgatewayGFSunInverterMQTT();
|
|
uint64_t getUInt64fromHex(char const* str);
|
|
void setupIR();
|
|
void IRtoMQTT();
|
|
void MQTTtoIR(char* topicOri, JsonObject& IRdata);
|
|
void setupLORA();
|
|
void LORAtoMQTT();
|
|
void MQTTtoLORA(char* topicOri, JsonObject& LORAdata);
|
|
void MQTTtoLORA(char* topicOri, char* LORAdata);
|
|
void pilightCallback(const String& protocol, const String& message, int status,
|
|
size_t repeats, const String& deviceID);
|
|
void setupPilight();
|
|
void savePilightConfig();
|
|
void loadPilightConfig();
|
|
void PilighttoMQTT();
|
|
void MQTTtoPilight(char* topicOri, JsonObject& Pilightdata);
|
|
extern void disablePilightReceive();
|
|
extern void enablePilightReceive();
|
|
static char* dec2binWzerofill(unsigned long Dec, unsigned int bitLength);
|
|
void RFtoMQTTdiscovery(SIGNAL_SIZE_UL_ULL MQTTvalue);
|
|
void setupRF();
|
|
void RFtoMQTT();
|
|
void MQTTtoRF(char* topicOri, char* datacallback);
|
|
void MQTTtoRF(char* topicOri, JsonObject& RFdata);
|
|
void disableRFReceive();
|
|
void enableRFReceive();
|
|
void setupRF2();
|
|
void RF2toMQTTdiscovery(JsonObject& data);
|
|
void RF2toMQTT();
|
|
void rf2Callback(unsigned int period, unsigned long address, unsigned long groupBit, unsigned long unit, unsigned long switchType);
|
|
void MQTTtoRF2(char* topicOri, char* datacallback);
|
|
void MQTTtoRF2(char* topicOri, JsonObject& RF2data);
|
|
void disableRF2Receive();
|
|
void enableRF2Receive();
|
|
uint32_t gc_checksum();
|
|
void eeprom_setup();
|
|
void setupRFM69(void);
|
|
bool RFM69toMQTT(void);
|
|
void MQTTtoRFM69(char* topicOri, char* datacallback);
|
|
void MQTTtoRFM69(char* topicOri, JsonObject& RFM69data);
|
|
void setupRS232();
|
|
void RS232toMQTT();
|
|
void MQTTtoRS232(char* topicOri, JsonObject& RS232data);
|
|
void rtl_433_Callback(char* message);
|
|
void setupRTL_433();
|
|
void RTL_433Loop();
|
|
extern void MQTTtoRTL_433(char* topicOri, JsonObject& RTLdata);
|
|
extern void enableRTLreceive();
|
|
extern void disableRTLreceive();
|
|
extern int getRTLMinimumRSSI();
|
|
extern int getRTLCurrentRSSI();
|
|
extern int getRTLMessageCount();
|
|
void setupSRFB();
|
|
void _rfbSend(byte* message);
|
|
void _rfbSend(byte* message, int times);
|
|
bool SRFBtoMQTT();
|
|
void _rfbDecode();
|
|
void _rfbAck();
|
|
bool _rfbToArray(const char* in, byte* out);
|
|
bool _rfbToChar(byte* in, char* out);
|
|
void MQTTtoSRFB(char* topicOri, char* datacallback);
|
|
void MQTTtoSRFB(char* topicOri, JsonObject& SRFBdata);
|
|
void PairedDeviceAdded(byte newID);
|
|
void setupWeatherStation();
|
|
void sendWindSpeedData(byte id, float wind_speed, byte battery_status);
|
|
void sendRainData(byte id, float rain_volume, byte battery_status);
|
|
void sendWindData(byte id, int wind_direction, float wind_gust, byte battery_status);
|
|
void sendTemperatureData(byte id, float temperature, int humidity, byte battery_status);
|
|
void ZgatewayWeatherStationtoMQTT();
|
|
String getMacAddress();
|
|
String getUniqueId(String name, String sufix);
|
|
void createDiscoveryFromList(const char* mac,
|
|
const char* sensorList[][9],
|
|
int sensorCount,
|
|
const char* device_name,
|
|
const char* device_manufacturer,
|
|
const char* device_model);
|
|
void announceDeviceTrigger(bool use_gateway_info, char* topic, char* type, char* subtype, char* unique_id, char* device_name, char* device_manufacturer, char* device_model, char* device_mac);
|
|
void createDiscovery(const char* sensor_type,
|
|
const char* st_topic, const char* s_name, const char* unique_id,
|
|
const char* availability_topic, const char* device_class, const char* value_template,
|
|
const char* payload_on, const char* payload_off, const char* unit_of_meas,
|
|
int off_delay,
|
|
const char* payload_available, const char* payload_not_avalaible, bool gateway_entity, const char* cmd_topic,
|
|
const char* device_name, const char* device_manufacturer, const char* device_model, const char* device_mac, bool retainCmd,
|
|
const char* state_class, const char* state_off, const char* state_on);
|
|
void pubMqttDiscovery();
|
|
void setupADC();
|
|
void MeasureADC();
|
|
void setupZsensorAHTx0();
|
|
void MeasureAHTTempHum();
|
|
void setupZsensorBH1750();
|
|
void MeasureLightIntensity();
|
|
void setupZsensorBME280();
|
|
void MeasureTempHumAndPressure();
|
|
void setupDHT();
|
|
void MeasureTempAndHum();
|
|
void setupZsensorDS1820();
|
|
void pubOneWire_HADiscovery();
|
|
void MeasureDS1820Temp();
|
|
void setupGPIOInput();
|
|
void MeasureGPIOInput();
|
|
void setupGPIOKeyCode();
|
|
void MeasureGPIOKeyCode();
|
|
void setupHCSR04();
|
|
void MeasureDistance();
|
|
void setupHCSR501();
|
|
void MeasureHCSR501();
|
|
void setupZsensorHTU21();
|
|
void MeasureTempHum();
|
|
void setupINA226();
|
|
void MeasureINA226();
|
|
static void writeRegister(byte reg, word value);
|
|
static word readRegister(byte reg);
|
|
void setupSHTC3();
|
|
void MeasureTempAndHum();
|
|
void displaySensorDetails(void);
|
|
void setupZsensorTSL2561();
|
|
void MeasureLightIntensityTSL2561();
|
|
#line 249 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/main.ino"
|
|
void revert_hex_data(const char* in, char* out, int l) {
|
|
|
|
int i = l - 2, j = 0;
|
|
while (i != -2) {
|
|
if (i % 2 == 0)
|
|
out[j] = in[i + 1];
|
|
else
|
|
out[j] = in[i - 1];
|
|
j++;
|
|
i--;
|
|
}
|
|
out[l - 1] = '\0';
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
long value_from_hex_data(const char* service_data, int offset, int data_length, bool reverse, bool canBeNegative = true) {
|
|
char data[data_length + 1];
|
|
memcpy(data, &service_data[offset], data_length);
|
|
data[data_length] = '\0';
|
|
long value;
|
|
if (reverse) {
|
|
|
|
char rev_data[data_length + 1];
|
|
revert_hex_data(data, rev_data, data_length + 1);
|
|
value = strtol(rev_data, NULL, 16);
|
|
} else {
|
|
value = strtol(data, NULL, 16);
|
|
}
|
|
if (value > 65000 && data_length <= 4 && canBeNegative)
|
|
value = value - 65535;
|
|
Log.trace(F("value %D" CR), value);
|
|
return value;
|
|
}
|
|
|
|
char* ip2CharArray(IPAddress ip) {
|
|
static char a[16];
|
|
sprintf(a, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
|
|
return a;
|
|
}
|
|
|
|
bool to_bool(String const& s) {
|
|
return s != "0";
|
|
}
|
|
# 303 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/main.ino"
|
|
void pub(const char* topicori, const char* payload, bool retainFlag) {
|
|
String topic = String(mqtt_topic) + String(gateway_name) + String(topicori);
|
|
pubMQTT(topic.c_str(), payload, retainFlag);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void pub(const char* topicori, JsonObject& data) {
|
|
String dataAsString = "";
|
|
serializeJson(data, dataAsString);
|
|
Log.notice(F("Send on %s msg %s" CR), topicori, dataAsString.c_str());
|
|
digitalWrite(LED_SEND_RECEIVE, LED_SEND_RECEIVE_ON);
|
|
String topic = String(mqtt_topic) + String(gateway_name) + String(topicori);
|
|
#if valueAsATopic
|
|
# ifdef ZgatewayPilight
|
|
String value = data["value"];
|
|
String protocol = data["protocol"];
|
|
if (value != "null" && value != 0) {
|
|
topic = topic + "/" + protocol + "/" + value;
|
|
}
|
|
# else
|
|
SIGNAL_SIZE_UL_ULL value = data["value"];
|
|
if (value != 0) {
|
|
topic = topic + "/" + toString(value);
|
|
}
|
|
# endif
|
|
#endif
|
|
|
|
#if jsonPublishing
|
|
Log.trace(F("jsonPubl - ON" CR));
|
|
pubMQTT(topic, dataAsString.c_str());
|
|
#endif
|
|
|
|
#if simplePublishing
|
|
Log.trace(F("simplePub - ON" CR));
|
|
|
|
for (JsonPair p : data) {
|
|
# if defined(ESP8266)
|
|
yield();
|
|
# endif
|
|
if (p.value().is<SIGNAL_SIZE_UL_ULL>() && strcmp(p.key().c_str(), "rssi") != 0) {
|
|
if (strcmp(p.key().c_str(), "value") == 0) {
|
|
pubMQTT(topic, p.value().as<SIGNAL_SIZE_UL_ULL>());
|
|
} else {
|
|
pubMQTT(topic + "/" + String(p.key().c_str()), p.value().as<SIGNAL_SIZE_UL_ULL>());
|
|
}
|
|
} else if (p.value().is<int>()) {
|
|
pubMQTT(topic + "/" + String(p.key().c_str()), p.value().as<int>());
|
|
} else if (p.value().is<float>()) {
|
|
pubMQTT(topic + "/" + String(p.key().c_str()), p.value().as<float>());
|
|
} else if (p.value().is<char*>()) {
|
|
pubMQTT(topic + "/" + String(p.key().c_str()), p.value().as<const char*>());
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void pub(const char* topicori, const char* payload) {
|
|
String topic = String(mqtt_topic) + String(gateway_name) + String(topicori);
|
|
pubMQTT(topic, payload);
|
|
}
|
|
# 382 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/main.ino"
|
|
void pub_custom_topic(const char* topic, JsonObject& data, boolean retain) {
|
|
String buffer = "";
|
|
serializeJson(data, buffer);
|
|
pubMQTT(topic, buffer.c_str(), retain);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void pubMQTT(const char* topic, const char* payload) {
|
|
pubMQTT(topic, payload, false);
|
|
}
|
|
# 405 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/main.ino"
|
|
void pubMQTT(const char* topic, const char* payload, bool retainFlag) {
|
|
if (client.connected()) {
|
|
Log.trace(F("[ OMG->MQTT ] topic: %s msg: %s " CR), topic, payload);
|
|
#if AWS_IOT
|
|
client.publish(topic, payload);
|
|
#else
|
|
client.publish(topic, payload, retainFlag);
|
|
#endif
|
|
} else {
|
|
Log.warning(F("Client not connected, aborting thes publication" CR));
|
|
}
|
|
}
|
|
|
|
void pubMQTT(String topic, const char* payload) {
|
|
pubMQTT(topic.c_str(), payload);
|
|
}
|
|
|
|
void pubMQTT(const char* topic, unsigned long payload) {
|
|
char val[11];
|
|
sprintf(val, "%lu", payload);
|
|
pubMQTT(topic, val);
|
|
}
|
|
|
|
void pubMQTT(const char* topic, unsigned long long payload) {
|
|
char val[21];
|
|
sprintf(val, "%llu", payload);
|
|
pubMQTT(topic, val);
|
|
}
|
|
|
|
void pubMQTT(const char* topic, String payload) {
|
|
pubMQTT(topic, payload.c_str());
|
|
}
|
|
|
|
void pubMQTT(String topic, String payload) {
|
|
pubMQTT(topic.c_str(), payload.c_str());
|
|
}
|
|
|
|
void pubMQTT(String topic, int payload) {
|
|
char val[12];
|
|
sprintf(val, "%d", payload);
|
|
pubMQTT(topic.c_str(), val);
|
|
}
|
|
|
|
void pubMQTT(String topic, unsigned long long payload) {
|
|
char val[21];
|
|
sprintf(val, "%llu", payload);
|
|
pubMQTT(topic.c_str(), val);
|
|
}
|
|
|
|
void pubMQTT(String topic, float payload) {
|
|
char val[12];
|
|
dtostrf(payload, 3, 1, val);
|
|
pubMQTT(topic.c_str(), val);
|
|
}
|
|
|
|
void pubMQTT(const char* topic, float payload) {
|
|
char val[12];
|
|
dtostrf(payload, 3, 1, val);
|
|
pubMQTT(topic, val);
|
|
}
|
|
|
|
void pubMQTT(const char* topic, int payload) {
|
|
char val[12];
|
|
sprintf(val, "%d", payload);
|
|
pubMQTT(topic, val);
|
|
}
|
|
|
|
void pubMQTT(const char* topic, unsigned int payload) {
|
|
char val[12];
|
|
sprintf(val, "%u", payload);
|
|
pubMQTT(topic, val);
|
|
}
|
|
|
|
void pubMQTT(const char* topic, long payload) {
|
|
char val[11];
|
|
sprintf(val, "%ld", payload);
|
|
pubMQTT(topic, val);
|
|
}
|
|
|
|
void pubMQTT(const char* topic, double payload) {
|
|
char val[16];
|
|
sprintf(val, "%f", payload);
|
|
pubMQTT(topic, val);
|
|
}
|
|
|
|
void pubMQTT(String topic, unsigned long payload) {
|
|
char val[11];
|
|
sprintf(val, "%lu", payload);
|
|
pubMQTT(topic.c_str(), val);
|
|
}
|
|
|
|
bool cmpToMainTopic(const char* topicOri, const char* toAdd) {
|
|
|
|
|
|
if (strncmp(topicOri, mqtt_topic, strlen(mqtt_topic)) != 0)
|
|
return false;
|
|
|
|
topicOri += strlen(mqtt_topic);
|
|
|
|
if (strncmp(topicOri, gateway_name, strlen(gateway_name)) != 0)
|
|
return false;
|
|
topicOri += strlen(gateway_name);
|
|
if (strncmp(topicOri, toAdd, strlen(toAdd)) != 0)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
void connectMQTT() {
|
|
#ifndef ESPWifiManualSetup
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
checkButton();
|
|
# endif
|
|
#endif
|
|
|
|
Log.warning(F("MQTT connection..." CR));
|
|
char topic[mqtt_topic_max_size];
|
|
strcpy(topic, mqtt_topic);
|
|
strcat(topic, gateway_name);
|
|
strcat(topic, will_Topic);
|
|
client.setBufferSize(mqtt_max_packet_size);
|
|
#if AWS_IOT
|
|
if (client.connect(gateway_name, mqtt_user, mqtt_pass)) {
|
|
#else
|
|
if (client.connect(gateway_name, mqtt_user, mqtt_pass, topic, will_QoS, will_Retain, will_Message)) {
|
|
#endif
|
|
|
|
displayPrint("MQTT connected");
|
|
Log.notice(F("Connected to broker" CR));
|
|
failure_number_mqtt = 0;
|
|
|
|
pub(will_Topic, Gateway_AnnouncementMsg, will_Retain);
|
|
|
|
pub(version_Topic, OMG_VERSION, will_Retain);
|
|
|
|
char topic2[mqtt_topic_max_size];
|
|
strcpy(topic2, mqtt_topic);
|
|
strcat(topic2, gateway_name);
|
|
strcat(topic2, subjectMQTTtoX);
|
|
if (client.subscribe(topic2)) {
|
|
#ifdef ZgatewayRF
|
|
client.subscribe(subjectMultiGTWRF);
|
|
#endif
|
|
#ifdef ZgatewayIR
|
|
client.subscribe(subjectMultiGTWIR);
|
|
#endif
|
|
#ifdef MQTT_HTTPS_FW_UPDATE
|
|
client.subscribe(subjectFWUpdate);
|
|
#endif
|
|
Log.trace(F("Subscription OK to the subjects %s" CR), topic2);
|
|
}
|
|
} else {
|
|
failure_number_mqtt++;
|
|
Log.warning(F("failure_number_mqtt: %d" CR), failure_number_mqtt);
|
|
Log.warning(F("failed, rc=%d" CR), client.state());
|
|
#if defined(ESP32)
|
|
if (mqtt_secure)
|
|
Log.warning(F("failed, ssl error code=%d" CR), ((WiFiClientSecure*)eClient)->lastError(nullptr, 0));
|
|
#elif defined(ESP8266)
|
|
if (mqtt_secure)
|
|
Log.warning(F("failed, ssl error code=%d" CR), ((WiFiClientSecure*)eClient)->getLastSSLError());
|
|
#endif
|
|
digitalWrite(LED_ERROR, LED_ERROR_ON);
|
|
delay(2000);
|
|
digitalWrite(LED_ERROR, !LED_ERROR_ON);
|
|
delay(5000);
|
|
if (failure_number_mqtt > maxRetryWatchDog) {
|
|
watchdogReboot(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void callback(char* topic, byte* payload, unsigned int length) {
|
|
|
|
|
|
|
|
Log.trace(F("Hey I got a callback %s" CR), topic);
|
|
|
|
byte* p = (byte*)malloc(length + 1);
|
|
|
|
memcpy(p, payload, length);
|
|
|
|
p[length] = '\0';
|
|
|
|
if ((strstr(topic, subjectMultiGTWKey) != NULL) ||
|
|
(strstr(topic, subjectGTWSendKey) != NULL) ||
|
|
(strstr(topic, subjectFWUpdate) != NULL))
|
|
receivingMQTT(topic, (char*)p);
|
|
|
|
|
|
free(p);
|
|
}
|
|
|
|
void setup() {
|
|
|
|
Serial.begin(SERIAL_BAUD);
|
|
Log.begin(LOG_LEVEL, &Serial);
|
|
Log.notice(F(CR "************* WELCOME TO OpenMQTTGateway **************" CR));
|
|
|
|
|
|
pinMode(LED_SEND_RECEIVE, OUTPUT);
|
|
pinMode(LED_INFO, OUTPUT);
|
|
pinMode(LED_ERROR, OUTPUT);
|
|
digitalWrite(LED_SEND_RECEIVE, !LED_SEND_RECEIVE_ON);
|
|
digitalWrite(LED_INFO, !LED_INFO_ON);
|
|
digitalWrite(LED_ERROR, !LED_ERROR_ON);
|
|
|
|
#if defined(ESP8266) || defined(ESP32)
|
|
# ifdef ESP8266
|
|
# ifndef ZgatewaySRFB
|
|
Serial.end();
|
|
Serial.begin(SERIAL_BAUD, SERIAL_8N1, SERIAL_TX_ONLY);
|
|
# endif
|
|
# elif ESP32
|
|
preferences.begin(Gateway_Short_Name, false);
|
|
lowpowermode = preferences.getUInt("lowpowermode", DEFAULT_LOW_POWER_MODE);
|
|
preferences.end();
|
|
# if defined(ZboardM5STICKC) || defined(ZboardM5STICKCP) || defined(ZboardM5STACK) || defined(ZboardM5TOUGH)
|
|
setupM5();
|
|
# endif
|
|
# if defined(ZboardHELTEC)
|
|
setupHELTEC();
|
|
modules.add(ZboardHELTEC);
|
|
# endif
|
|
Log.notice(F("OpenMQTTGateway Version: " OMG_VERSION CR));
|
|
# endif
|
|
|
|
# ifdef USE_MAC_AS_GATEWAY_NAME
|
|
String s = WiFi.macAddress();
|
|
sprintf(gateway_name, "%.2s%.2s%.2s%.2s%.2s%.2s",
|
|
s.c_str(), s.c_str() + 3, s.c_str() + 6, s.c_str() + 9, s.c_str() + 12, s.c_str() + 15);
|
|
snprintf(WifiManager_ssid, MAC_NAME_MAX_LEN, "%s_%s", Gateway_Short_Name, gateway_name);
|
|
strcpy(ota_hostname, WifiManager_ssid);
|
|
Log.notice(F("OTA Hostname: %s.local" CR), ota_hostname);
|
|
# endif
|
|
|
|
# ifdef ESP32_ETHERNET
|
|
setup_ethernet_esp32();
|
|
# else
|
|
# if defined(ESPWifiManualSetup)
|
|
setup_wifi();
|
|
# else
|
|
setup_wifimanager(false);
|
|
# endif
|
|
Log.trace(F("OpenMQTTGateway mac: %s" CR), WiFi.macAddress().c_str());
|
|
Log.trace(F("OpenMQTTGateway ip: %s" CR), WiFi.localIP().toString().c_str());
|
|
# endif
|
|
|
|
setOTA();
|
|
#else
|
|
|
|
|
|
Serial.begin(SERIAL_BAUD);
|
|
|
|
setup_ethernet();
|
|
#endif
|
|
|
|
#if defined(ESP8266) || defined(ESP32)
|
|
if (mqtt_secure) {
|
|
eClient = new WiFiClientSecure;
|
|
setupTLS(MQTT_SECURE_SELF_SIGNED, mqtt_ss_index);
|
|
} else {
|
|
eClient = new WiFiClient;
|
|
}
|
|
#else
|
|
eClient = new EthernetClient;
|
|
#endif
|
|
client.setClient(*(Client*)eClient);
|
|
|
|
#if defined(MDNS_SD) && (defined(ESP8266) || defined(ESP32))
|
|
Log.trace(F("Connecting to MQTT by mDNS without MQTT hostname" CR));
|
|
connectMQTTmdns();
|
|
#else
|
|
uint16_t port = strtol(mqtt_port, NULL, 10);
|
|
Log.trace(F("Port: %l" CR), port);
|
|
Log.trace(F("Mqtt server: %s" CR), mqtt_server);
|
|
client.setServer(mqtt_server, port);
|
|
#endif
|
|
|
|
client.setCallback(callback);
|
|
|
|
delay(1500);
|
|
|
|
#ifdef ZactuatorONOFF
|
|
pinMode(ACTUATOR_ONOFF_GPIO, OUTPUT);
|
|
digitalWrite(ACTUATOR_ONOFF_GPIO, ACTUATOR_ONOFF_DEFAULT);
|
|
#endif
|
|
#ifdef ZsensorBME280
|
|
setupZsensorBME280();
|
|
modules.add(ZsensorBME280);
|
|
#endif
|
|
#ifdef ZsensorHTU21
|
|
setupZsensorHTU21();
|
|
modules.add(ZsensorHTU21);
|
|
#endif
|
|
#ifdef ZsensorAHTx0
|
|
setupZsensorAHTx0();
|
|
modules.add(ZsensorAHTx0);
|
|
#endif
|
|
#ifdef ZsensorBH1750
|
|
setupZsensorBH1750();
|
|
modules.add(ZsensorBH1750);
|
|
#endif
|
|
#ifdef ZsensorTSL2561
|
|
setupZsensorTSL2561();
|
|
modules.add(ZsensorTSL2561);
|
|
#endif
|
|
#ifdef Zgateway2G
|
|
setup2G();
|
|
modules.add(Zgateway2G);
|
|
#endif
|
|
#ifdef ZgatewayIR
|
|
setupIR();
|
|
modules.add(ZgatewayIR);
|
|
#endif
|
|
#ifdef ZgatewayLORA
|
|
setupLORA();
|
|
modules.add(ZgatewayLORA);
|
|
#endif
|
|
#ifdef ZgatewayRF
|
|
setupRF();
|
|
modules.add(ZgatewayRF);
|
|
#define ACTIVE_RECEIVER ACTIVE_RF
|
|
#endif
|
|
#ifdef ZgatewayRF2
|
|
setupRF2();
|
|
modules.add(ZgatewayRF2);
|
|
# ifdef ACTIVE_RECEIVER
|
|
#undef ACTIVE_RECEIVER
|
|
# endif
|
|
#define ACTIVE_RECEIVER ACTIVE_RF2
|
|
#endif
|
|
#ifdef ZgatewayPilight
|
|
setupPilight();
|
|
modules.add(ZgatewayPilight);
|
|
disablePilightReceive();
|
|
# ifdef ACTIVE_RECEIVER
|
|
#undef ACTIVE_RECEIVER
|
|
# endif
|
|
#define ACTIVE_RECEIVER ACTIVE_PILIGHT
|
|
#endif
|
|
#ifdef ZgatewayWeatherStation
|
|
setupWeatherStation();
|
|
modules.add(ZgatewayWeatherStation);
|
|
#endif
|
|
#ifdef ZgatewayGFSunInverter
|
|
setupGFSunInverter();
|
|
modules.add(ZgatewayGFSunInverter);
|
|
#endif
|
|
#ifdef ZgatewaySRFB
|
|
setupSRFB();
|
|
modules.add(ZgatewaySRFB);
|
|
#endif
|
|
#ifdef ZgatewayBT
|
|
setupBT();
|
|
modules.add(ZgatewayBT);
|
|
#endif
|
|
#ifdef ZgatewayRFM69
|
|
setupRFM69();
|
|
modules.add(ZgatewayRFM69);
|
|
#endif
|
|
#ifdef ZsensorINA226
|
|
setupINA226();
|
|
modules.add(ZsensorINA226);
|
|
#endif
|
|
#ifdef ZsensorHCSR501
|
|
setupHCSR501();
|
|
modules.add(ZsensorHCSR501);
|
|
#endif
|
|
#ifdef ZsensorHCSR04
|
|
setupHCSR04();
|
|
modules.add(ZsensorHCSR04);
|
|
#endif
|
|
#ifdef ZsensorGPIOInput
|
|
setupGPIOInput();
|
|
modules.add(ZsensorGPIOInput);
|
|
#endif
|
|
#ifdef ZsensorGPIOKeyCode
|
|
setupGPIOKeyCode();
|
|
modules.add(ZsensorGPIOKeyCode);
|
|
#endif
|
|
#ifdef ZactuatorFASTLED
|
|
setupFASTLED();
|
|
modules.add(ZactuatorFASTLED);
|
|
#endif
|
|
#ifdef ZactuatorPWM
|
|
setupPWM();
|
|
modules.add(ZactuatorPWM);
|
|
#endif
|
|
#ifdef ZactuatorSomfy
|
|
setupSomfy();
|
|
modules.add(ZactuatorSomfy);
|
|
#endif
|
|
#ifdef ZsensorDS1820
|
|
setupZsensorDS1820();
|
|
modules.add(ZsensorDS1820);
|
|
#endif
|
|
#ifdef ZsensorADC
|
|
setupADC();
|
|
modules.add(ZsensorADC);
|
|
#endif
|
|
#ifdef ZsensorDHT
|
|
setupDHT();
|
|
modules.add(ZsensorDHT);
|
|
#endif
|
|
#ifdef ZgatewayRS232
|
|
setupRS232();
|
|
modules.add(ZgatewayRS232);
|
|
#endif
|
|
#ifdef ZsensorSHTC3
|
|
setupSHTC3();
|
|
#endif
|
|
#ifdef ZgatewayRTL_433
|
|
setupRTL_433();
|
|
modules.add(ZgatewayRTL_433);
|
|
# ifdef ACTIVE_RECEIVER
|
|
#undef ACTIVE_RECEIVER
|
|
# endif
|
|
#define ACTIVE_RECEIVER ACTIVE_RTL
|
|
#endif
|
|
#if defined(ZgatewayRTL_433) || defined(ZgatewayRF) || defined(ZgatewayPilight) || defined(ZgatewayRF2)
|
|
# ifdef DEFAULT_RECEIVER
|
|
activeReceiver = DEFAULT_RECEIVER;
|
|
# else
|
|
activeReceiver = ACTIVE_RECEIVER;
|
|
# endif
|
|
enableActiveReceiver(true);
|
|
#endif
|
|
Log.trace(F("mqtt_max_packet_size: %d" CR), mqtt_max_packet_size);
|
|
|
|
#ifndef ARDUINO_AVR_UNO
|
|
char jsonChar[100];
|
|
serializeJson(modules, jsonChar, measureJson(modules) + 1);
|
|
Log.notice(F("OpenMQTTGateway modules: %s" CR), jsonChar);
|
|
#endif
|
|
Log.notice(F("************** Setup OpenMQTTGateway end **************" CR));
|
|
}
|
|
|
|
#if defined(ESP8266) || defined(ESP32)
|
|
|
|
bool wifi_reconnect_bypass() {
|
|
uint8_t wifi_autoreconnect_cnt = 0;
|
|
# ifdef ESP32
|
|
while (WiFi.status() != WL_CONNECTED && wifi_autoreconnect_cnt < maxConnectionRetryWifi) {
|
|
# else
|
|
while (WiFi.waitForConnectResult() != WL_CONNECTED && wifi_autoreconnect_cnt < maxConnectionRetryWifi) {
|
|
# endif
|
|
Log.notice(F("Attempting Wifi connection with saved AP: %d" CR), wifi_autoreconnect_cnt);
|
|
WiFi.begin();
|
|
delay(500);
|
|
wifi_autoreconnect_cnt++;
|
|
}
|
|
if (wifi_autoreconnect_cnt < maxConnectionRetryWifi) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void setOTA() {
|
|
|
|
ArduinoOTA.setPort(ota_port);
|
|
|
|
|
|
ArduinoOTA.setHostname(ota_hostname);
|
|
|
|
|
|
ArduinoOTA.setPassword(ota_password);
|
|
|
|
ArduinoOTA.onStart([]() {
|
|
Log.trace(F("Start OTA, lock other functions" CR));
|
|
digitalWrite(LED_SEND_RECEIVE, LED_SEND_RECEIVE_ON);
|
|
digitalWrite(LED_ERROR, LED_ERROR_ON);
|
|
# if defined(ZgatewayBT) && defined(ESP32)
|
|
stopProcessing();
|
|
# endif
|
|
lpDisplayPrint("OTA in progress");
|
|
});
|
|
ArduinoOTA.onEnd([]() {
|
|
Log.trace(F("\nOTA done" CR));
|
|
digitalWrite(LED_SEND_RECEIVE, !LED_SEND_RECEIVE_ON);
|
|
digitalWrite(LED_ERROR, !LED_ERROR_ON);
|
|
# if defined(ZgatewayBT) && defined(ESP32)
|
|
startProcessing();
|
|
# endif
|
|
lpDisplayPrint("OTA done");
|
|
});
|
|
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
|
|
Log.trace(F("Progress: %u%%\r" CR), (progress / (total / 100)));
|
|
});
|
|
ArduinoOTA.onError([](ota_error_t error) {
|
|
digitalWrite(LED_SEND_RECEIVE, !LED_SEND_RECEIVE_ON);
|
|
digitalWrite(LED_ERROR, !LED_ERROR_ON);
|
|
# if defined(ZgatewayBT) && defined(ESP32)
|
|
startProcessing();
|
|
# endif
|
|
Serial.printf("Error[%u]: ", error);
|
|
if (error == OTA_AUTH_ERROR)
|
|
Log.error(F("Auth Failed" CR));
|
|
else if (error == OTA_BEGIN_ERROR)
|
|
Log.error(F("Begin Failed" CR));
|
|
else if (error == OTA_CONNECT_ERROR)
|
|
Log.error(F("Connect Failed" CR));
|
|
else if (error == OTA_RECEIVE_ERROR)
|
|
Log.error(F("Receive Failed" CR));
|
|
else if (error == OTA_END_ERROR)
|
|
Log.error(F("End Failed" CR));
|
|
});
|
|
ArduinoOTA.begin();
|
|
}
|
|
|
|
void setupTLS(bool self_signed, uint8_t index) {
|
|
configTime(0, 0, NTP_SERVER);
|
|
WiFiClientSecure* sClient = (WiFiClientSecure*)eClient;
|
|
# if MQTT_SECURE_SELF_SIGNED
|
|
if (self_signed) {
|
|
Log.notice(F("Using self signed cert index %u" CR), index);
|
|
# if defined(ESP32)
|
|
sClient->setCACert(certs_array[index].server_cert);
|
|
# if MQTT_SECURE_SELF_SIGNED_CLIENT
|
|
sClient->setCertificate(certs_array[index].client_cert);
|
|
sClient->setPrivateKey(certs_array[index].client_key);
|
|
# endif
|
|
# elif defined(ESP8266)
|
|
caCert.append(certs_array[index].server_cert);
|
|
sClient->setTrustAnchors(&caCert);
|
|
sClient->setBufferSizes(512, 512);
|
|
# if MQTT_SECURE_SELF_SIGNED_CLIENT
|
|
if (pClCert != nullptr) {
|
|
delete pClCert;
|
|
}
|
|
if (pClKey != nullptr) {
|
|
delete pClKey;
|
|
}
|
|
pClCert = new X509List(certs_array[index].client_cert);
|
|
pClKey = new PrivateKey(certs_array[index].client_key);
|
|
sClient->setClientRSACert(pClCert, pClKey);
|
|
# endif
|
|
# endif
|
|
} else
|
|
# endif
|
|
{
|
|
if (mqtt_cert.length() > 0) {
|
|
# if defined(ESP32)
|
|
sClient->setCACert(mqtt_cert.c_str());
|
|
} else {
|
|
sClient->setCACert(certificate);
|
|
}
|
|
# elif defined(ESP8266)
|
|
caCert.append(mqtt_cert.c_str());
|
|
} else {
|
|
caCert.append(certificate);
|
|
}
|
|
sClient->setTrustAnchors(&caCert);
|
|
sClient->setBufferSizes(512, 512);
|
|
# endif
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(ESPWifiManualSetup)
|
|
void setup_wifi() {
|
|
WiFi.mode(WIFI_STA);
|
|
wifiMulti.addAP(wifi_ssid, wifi_password);
|
|
Log.trace(F("Connecting to %s" CR), wifi_ssid);
|
|
# ifdef wifi_ssid1
|
|
wifiMulti.addAP(wifi_ssid1, wifi_password1);
|
|
Log.trace(F("Connecting to %s" CR), wifi_ssid1);
|
|
# endif
|
|
delay(10);
|
|
|
|
|
|
|
|
# ifdef NetworkAdvancedSetup
|
|
IPAddress ip_adress(ip);
|
|
IPAddress gateway_adress(gateway);
|
|
IPAddress subnet_adress(subnet);
|
|
IPAddress dns_adress(Dns);
|
|
if (!WiFi.config(ip_adress, gateway_adress, subnet_adress, dns_adress)) {
|
|
Log.error(F("Wifi STA Failed to configure" CR));
|
|
}
|
|
|
|
# endif
|
|
|
|
while (wifiMulti.run() != WL_CONNECTED) {
|
|
delay(500);
|
|
Log.trace(F("." CR));
|
|
failure_number_ntwk++;
|
|
# if defined(ESP32) && defined(ZgatewayBT)
|
|
if (lowpowermode) {
|
|
if (failure_number_ntwk > maxConnectionRetryWifi) {
|
|
lowPowerESP32();
|
|
}
|
|
} else {
|
|
if (failure_number_ntwk > maxRetryWatchDog) {
|
|
watchdogReboot(2);
|
|
}
|
|
}
|
|
# else
|
|
if (failure_number_ntwk > maxRetryWatchDog) {
|
|
watchdogReboot(2);
|
|
}
|
|
# endif
|
|
}
|
|
Log.notice(F("WiFi ok with manual config credentials" CR));
|
|
}
|
|
|
|
#elif defined(ESP8266) || defined(ESP32)
|
|
|
|
WiFiManager wifiManager;
|
|
|
|
|
|
bool shouldSaveConfig = false;
|
|
|
|
|
|
|
|
void saveConfigCallback() {
|
|
Log.trace(F("Should save config" CR));
|
|
shouldSaveConfig = true;
|
|
}
|
|
|
|
# ifdef TRIGGER_GPIO
|
|
void checkButton() {
|
|
# if defined(INPUT_GPIO) && defined(ZsensorGPIOInput) && INPUT_GPIO == TRIGGER_GPIO
|
|
MeasureGPIOInput();
|
|
# else
|
|
|
|
if (digitalRead(TRIGGER_GPIO) == LOW) {
|
|
|
|
delay(50);
|
|
if (digitalRead(TRIGGER_GPIO) == LOW) {
|
|
Log.trace(F("Trigger button Pressed" CR));
|
|
|
|
delay(3000);
|
|
if (digitalRead(TRIGGER_GPIO) == LOW) {
|
|
Log.trace(F("Button Held" CR));
|
|
Log.notice(F("Erasing ESP Config, restarting" CR));
|
|
setup_wifimanager(true);
|
|
}
|
|
}
|
|
}
|
|
# endif
|
|
}
|
|
# else
|
|
void checkButton() {}
|
|
# endif
|
|
|
|
void eraseAndRestart() {
|
|
Log.trace(F("Formatting requested, result: %d" CR), SPIFFS.format());
|
|
|
|
# if defined(ESP8266)
|
|
WiFi.disconnect(true);
|
|
wifiManager.resetSettings();
|
|
delay(5000);
|
|
ESP.reset();
|
|
# else
|
|
nvs_flash_erase();
|
|
ESP.restart();
|
|
# endif
|
|
}
|
|
|
|
void saveMqttConfig() {
|
|
Log.trace(F("saving config" CR));
|
|
DynamicJsonDocument json(512 + ota_server_cert.length() + mqtt_cert.length());
|
|
json["mqtt_server"] = mqtt_server;
|
|
json["mqtt_port"] = mqtt_port;
|
|
json["mqtt_user"] = mqtt_user;
|
|
json["mqtt_pass"] = mqtt_pass;
|
|
json["mqtt_topic"] = mqtt_topic;
|
|
json["gateway_name"] = gateway_name;
|
|
json["mqtt_broker_secure"] = mqtt_secure;
|
|
json["mqtt_broker_cert"] = mqtt_cert;
|
|
json["mqtt_ss_index"] = mqtt_ss_index;
|
|
json["ota_server_cert"] = ota_server_cert;
|
|
|
|
File configFile = SPIFFS.open("/config.json", "w");
|
|
if (!configFile) {
|
|
Log.error(F("failed to open config file for writing" CR));
|
|
}
|
|
|
|
serializeJsonPretty(json, Serial);
|
|
serializeJson(json, configFile);
|
|
configFile.close();
|
|
}
|
|
|
|
void setup_wifimanager(bool reset_settings) {
|
|
# ifdef TRIGGER_GPIO
|
|
pinMode(TRIGGER_GPIO, INPUT_PULLUP);
|
|
# endif
|
|
delay(10);
|
|
WiFi.mode(WIFI_STA);
|
|
|
|
if (reset_settings)
|
|
eraseAndRestart();
|
|
|
|
|
|
Log.trace(F("mounting FS..." CR));
|
|
|
|
if (SPIFFS.begin()) {
|
|
Log.trace(F("mounted file system" CR));
|
|
} else {
|
|
Log.warning(F("failed to mount FS -> formating" CR));
|
|
SPIFFS.format();
|
|
if (SPIFFS.begin())
|
|
Log.trace(F("mounted file system after formating" CR));
|
|
}
|
|
if (SPIFFS.exists("/config.json")) {
|
|
|
|
Log.trace(F("reading config file" CR));
|
|
File configFile = SPIFFS.open("/config.json", "r");
|
|
if (configFile) {
|
|
Log.trace(F("opened config file" CR));
|
|
DynamicJsonDocument json(configFile.size() * 2);
|
|
auto error = deserializeJson(json, configFile);
|
|
if (error) {
|
|
Log.error(F("deserialize config failed: %s, buffer capacity: %u" CR), error.c_str(), json.capacity());
|
|
}
|
|
serializeJsonPretty(json, Serial);
|
|
if (!json.isNull()) {
|
|
Log.trace(F("\nparsed json, size: %u" CR), json.memoryUsage());
|
|
if (json.containsKey("mqtt_server"))
|
|
strcpy(mqtt_server, json["mqtt_server"]);
|
|
if (json.containsKey("mqtt_port"))
|
|
strcpy(mqtt_port, json["mqtt_port"]);
|
|
if (json.containsKey("mqtt_user"))
|
|
strcpy(mqtt_user, json["mqtt_user"]);
|
|
if (json.containsKey("mqtt_pass"))
|
|
strcpy(mqtt_pass, json["mqtt_pass"]);
|
|
if (json.containsKey("mqtt_topic"))
|
|
strcpy(mqtt_topic, json["mqtt_topic"]);
|
|
if (json.containsKey("mqtt_broker_secure"))
|
|
mqtt_secure = json["mqtt_broker_secure"].as<bool>();
|
|
if (json.containsKey("mqtt_broker_cert"))
|
|
mqtt_cert = json["mqtt_broker_cert"].as<const char*>();
|
|
if (json.containsKey("mqtt_ss_index"))
|
|
mqtt_ss_index = json["mqtt_ss_index"].as<uint8_t>();
|
|
if (json.containsKey("gateway_name"))
|
|
strcpy(gateway_name, json["gateway_name"]);
|
|
if (json.containsKey("ota_server_cert"))
|
|
ota_server_cert = json["ota_server_cert"].as<const char*>();
|
|
} else {
|
|
Log.warning(F("failed to load json config" CR));
|
|
}
|
|
configFile.close();
|
|
}
|
|
}
|
|
|
|
wifiManager.setDebugOutput(WM_DEBUG_LEVEL);
|
|
|
|
|
|
|
|
|
|
# ifndef WIFIMNG_HIDE_MQTT_CONFIG
|
|
WiFiManagerParameter custom_mqtt_server("server", "mqtt server", mqtt_server, parameters_size);
|
|
WiFiManagerParameter custom_mqtt_port("port", "mqtt port", mqtt_port, 6);
|
|
WiFiManagerParameter custom_mqtt_user("user", "mqtt user", mqtt_user, parameters_size);
|
|
WiFiManagerParameter custom_mqtt_pass("pass", "mqtt pass", mqtt_pass, parameters_size);
|
|
WiFiManagerParameter custom_mqtt_topic("topic", "mqtt base topic", mqtt_topic, mqtt_topic_max_size);
|
|
WiFiManagerParameter custom_mqtt_secure("secure", "mqtt secure", "1", 1, mqtt_secure ? "type=\"checkbox\" checked" : "type=\"checkbox\"");
|
|
WiFiManagerParameter custom_mqtt_cert("cert", "mqtt broker cert", mqtt_cert.c_str(), 2048);
|
|
WiFiManagerParameter custom_gateway_name("name", "gateway name", gateway_name, parameters_size);
|
|
# endif
|
|
|
|
|
|
|
|
wifiManager.setConnectTimeout(WifiManager_TimeOut);
|
|
|
|
wifiManager.setConfigPortalTimeout(WifiManager_ConfigPortalTimeOut);
|
|
|
|
|
|
wifiManager.setSaveConfigCallback(saveConfigCallback);
|
|
|
|
|
|
# ifdef NetworkAdvancedSetup
|
|
Log.trace(F("Adv wifi cfg" CR));
|
|
IPAddress gateway_adress(gateway);
|
|
IPAddress subnet_adress(subnet);
|
|
IPAddress ip_adress(ip);
|
|
wifiManager.setSTAStaticIPConfig(ip_adress, gateway_adress, subnet_adress);
|
|
# endif
|
|
|
|
# ifndef WIFIMNG_HIDE_MQTT_CONFIG
|
|
|
|
wifiManager.addParameter(&custom_mqtt_server);
|
|
wifiManager.addParameter(&custom_mqtt_port);
|
|
wifiManager.addParameter(&custom_mqtt_user);
|
|
wifiManager.addParameter(&custom_mqtt_pass);
|
|
wifiManager.addParameter(&custom_mqtt_secure);
|
|
wifiManager.addParameter(&custom_mqtt_cert);
|
|
wifiManager.addParameter(&custom_gateway_name);
|
|
wifiManager.addParameter(&custom_mqtt_topic);
|
|
# endif
|
|
|
|
wifiManager.setMinimumSignalQuality(MinimumWifiSignalQuality);
|
|
|
|
if (!wifi_reconnect_bypass())
|
|
{
|
|
# ifdef ESP32
|
|
if (lowpowermode < 2) {
|
|
displayPrint("Connect your phone to WIFI AP:", WifiManager_ssid, WifiManager_password);
|
|
} else {
|
|
# ifdef ZgatewayBT
|
|
lowPowerESP32();
|
|
# endif
|
|
}
|
|
# endif
|
|
|
|
digitalWrite(LED_ERROR, LED_ERROR_ON);
|
|
digitalWrite(LED_INFO, LED_INFO_ON);
|
|
Log.notice(F("Connect your phone to WIFI AP: %s with PWD: %s" CR), WifiManager_ssid, WifiManager_password);
|
|
|
|
|
|
|
|
if (!wifiManager.autoConnect(WifiManager_ssid, WifiManager_password)) {
|
|
Log.warning(F("failed to connect and hit timeout" CR));
|
|
delay(3000);
|
|
|
|
watchdogReboot(3);
|
|
delay(5000);
|
|
}
|
|
digitalWrite(LED_ERROR, !LED_ERROR_ON);
|
|
digitalWrite(LED_INFO, !LED_INFO_ON);
|
|
}
|
|
|
|
displayPrint("Wifi connected");
|
|
|
|
if (shouldSaveConfig) {
|
|
|
|
# ifndef WIFIMNG_HIDE_MQTT_CONFIG
|
|
strcpy(mqtt_server, custom_mqtt_server.getValue());
|
|
strcpy(mqtt_port, custom_mqtt_port.getValue());
|
|
strcpy(mqtt_user, custom_mqtt_user.getValue());
|
|
strcpy(mqtt_pass, custom_mqtt_pass.getValue());
|
|
strcpy(mqtt_topic, custom_mqtt_topic.getValue());
|
|
strcpy(gateway_name, custom_gateway_name.getValue());
|
|
mqtt_secure = *custom_mqtt_secure.getValue();
|
|
|
|
int cert_len = strlen(custom_mqtt_cert.getValue());
|
|
if (cert_len) {
|
|
char* cert_in = (char*)custom_mqtt_cert.getValue();
|
|
while (*cert_in == ' ' || *cert_in == '\t') {
|
|
cert_in++;
|
|
}
|
|
|
|
char* cert_begin = cert_in;
|
|
while (*cert_in != NULL) {
|
|
if (*cert_in == ' ' && (strncmp((cert_in + 1), "CERTIFICATE", 11) != 0)) {
|
|
*cert_in = '\n';
|
|
}
|
|
cert_in++;
|
|
}
|
|
|
|
mqtt_cert = cert_begin;
|
|
}
|
|
# endif
|
|
|
|
saveMqttConfig();
|
|
}
|
|
}
|
|
# ifdef ESP32_ETHERNET
|
|
void setup_ethernet_esp32() {
|
|
bool ethBeginSuccess = false;
|
|
WiFi.onEvent(WiFiEvent);
|
|
# ifdef NetworkAdvancedSetup
|
|
Log.trace(F("Adv eth cfg" CR));
|
|
ETH.config(ip, gateway, subnet, Dns);
|
|
ethBeginSuccess = ETH.begin();
|
|
# else
|
|
Log.trace(F("Spl eth cfg" CR));
|
|
ethBeginSuccess = ETH.begin();
|
|
# endif
|
|
Log.trace(F("Connecting to Ethernet" CR));
|
|
while (!esp32EthConnected) {
|
|
delay(500);
|
|
Log.trace(F("." CR));
|
|
}
|
|
}
|
|
|
|
void WiFiEvent(WiFiEvent_t event) {
|
|
switch (event) {
|
|
case SYSTEM_EVENT_ETH_START:
|
|
Log.trace(F("Ethernet Started" CR));
|
|
ETH.setHostname(gateway_name);
|
|
break;
|
|
case SYSTEM_EVENT_ETH_CONNECTED:
|
|
Log.notice(F("Ethernet Connected" CR));
|
|
break;
|
|
case SYSTEM_EVENT_ETH_GOT_IP:
|
|
Log.trace(F("OpenMQTTGateway MAC: %s" CR), ETH.macAddress().c_str());
|
|
Log.trace(F("OpenMQTTGateway IP: %s" CR), ETH.localIP().toString().c_str());
|
|
Log.trace(F("OpenMQTTGateway link speed: %d Mbps" CR), ETH.linkSpeed());
|
|
esp32EthConnected = true;
|
|
break;
|
|
case SYSTEM_EVENT_ETH_DISCONNECTED:
|
|
Log.error(F("Ethernet Disconnected" CR));
|
|
esp32EthConnected = false;
|
|
break;
|
|
case SYSTEM_EVENT_ETH_STOP:
|
|
Log.error(F("Ethernet Stopped" CR));
|
|
esp32EthConnected = false;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
# endif
|
|
#else
|
|
void setup_ethernet() {
|
|
# ifdef NetworkAdvancedSetup
|
|
Log.trace(F("Adv eth cfg" CR));
|
|
Ethernet.begin(mac, ip, Dns, gateway, subnet);
|
|
# else
|
|
Log.trace(F("Spl eth cfg" CR));
|
|
Ethernet.begin(mac, ip);
|
|
# endif
|
|
if (Ethernet.hardwareStatus() == EthernetNoHardware) {
|
|
Log.error(F("Ethernet shield was not found." CR));
|
|
} else {
|
|
Log.trace(F("ip: %s " CR), Ethernet.localIP());
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(MDNS_SD) && (defined(ESP8266) || defined(ESP32))
|
|
void connectMQTTmdns() {
|
|
Log.trace(F("Browsing for MQTT service" CR));
|
|
int n = MDNS.queryService("mqtt", "tcp");
|
|
if (n == 0) {
|
|
Log.error(F("no services found" CR));
|
|
} else {
|
|
Log.trace(F("%d service(s) found" CR), n);
|
|
for (int i = 0; i < n; ++i) {
|
|
Log.trace(F("Service %d %s found" CR), i, MDNS.hostname(i).c_str());
|
|
Log.trace(F("IP %s Port %d" CR), MDNS.IP(i).toString().c_str(), MDNS.port(i));
|
|
}
|
|
if (n == 1) {
|
|
Log.trace(F("One MQTT server found setting parameters" CR));
|
|
client.setServer(MDNS.IP(0), int(MDNS.port(0)));
|
|
} else {
|
|
Log.error(F("Several MQTT servers found, please deactivate mDNS and set your default server" CR));
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void loop() {
|
|
#ifndef ESPWifiManualSetup
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
checkButton();
|
|
# endif
|
|
#endif
|
|
|
|
unsigned long now = millis();
|
|
|
|
|
|
if (now > (timer_led_measures + (TimeLedON * 1000))) {
|
|
timer_led_measures = millis();
|
|
digitalWrite(LED_INFO, !LED_INFO_ON);
|
|
digitalWrite(LED_SEND_RECEIVE, !LED_SEND_RECEIVE_ON);
|
|
}
|
|
|
|
#if defined(ESP8266) || defined(ESP32)
|
|
# ifdef ESP32_ETHERNET
|
|
if (esp32EthConnected) {
|
|
# else
|
|
if (WiFi.status() == WL_CONNECTED) {
|
|
# endif
|
|
ArduinoOTA.handle();
|
|
#else
|
|
if ((Ethernet.hardwareStatus() != EthernetW5100 && Ethernet.linkStatus() == LinkON) || (Ethernet.hardwareStatus() == EthernetW5100)) {
|
|
#endif
|
|
failure_number_ntwk = 0;
|
|
if (client.connected()) {
|
|
digitalWrite(LED_INFO, LED_INFO_ON);
|
|
failure_number_ntwk = 0;
|
|
|
|
client.loop();
|
|
|
|
#ifdef ZmqttDiscovery
|
|
if (disc) {
|
|
if (!connectedOnce || (discovery_republish_on_reconnect && !justReconnected)) {
|
|
|
|
|
|
pubMqttDiscovery();
|
|
}
|
|
}
|
|
#endif
|
|
connectedOnce = true;
|
|
justReconnected = true;
|
|
#if defined(ESP8266) || defined(ESP32) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__)
|
|
if (now > (timer_sys_measures + (TimeBetweenReadingSYS * 1000)) || !timer_sys_measures) {
|
|
timer_sys_measures = millis();
|
|
stateMeasures();
|
|
}
|
|
#endif
|
|
#ifdef ZsensorBME280
|
|
MeasureTempHumAndPressure();
|
|
#endif
|
|
#ifdef ZsensorHTU21
|
|
MeasureTempHum();
|
|
#endif
|
|
#ifdef ZsensorAHTx0
|
|
MeasureAHTTempHum();
|
|
#endif
|
|
#ifdef ZsensorHCSR04
|
|
MeasureDistance();
|
|
#endif
|
|
#ifdef ZsensorBH1750
|
|
MeasureLightIntensity();
|
|
#endif
|
|
#ifdef ZsensorTSL2561
|
|
MeasureLightIntensityTSL2561();
|
|
#endif
|
|
#ifdef ZsensorDHT
|
|
MeasureTempAndHum();
|
|
#endif
|
|
#ifdef ZsensorSHTC3
|
|
MeasureTempAndHum();
|
|
#endif
|
|
#ifdef ZsensorDS1820
|
|
MeasureDS1820Temp();
|
|
#endif
|
|
#ifdef ZsensorINA226
|
|
MeasureINA226();
|
|
#endif
|
|
#ifdef ZsensorHCSR501
|
|
MeasureHCSR501();
|
|
#endif
|
|
#ifdef ZsensorGPIOInput
|
|
MeasureGPIOInput();
|
|
#endif
|
|
#ifdef ZsensorGPIOKeyCode
|
|
MeasureGPIOKeyCode();
|
|
#endif
|
|
#ifdef ZsensorADC
|
|
MeasureADC();
|
|
#endif
|
|
#ifdef ZgatewayLORA
|
|
LORAtoMQTT();
|
|
#endif
|
|
#ifdef ZgatewayRF
|
|
RFtoMQTT();
|
|
#endif
|
|
#ifdef ZgatewayRF2
|
|
RF2toMQTT();
|
|
#endif
|
|
#ifdef ZgatewayWeatherStation
|
|
ZgatewayWeatherStationtoMQTT();
|
|
#endif
|
|
#ifdef ZgatewayGFSunInverter
|
|
ZgatewayGFSunInverterMQTT();
|
|
#endif
|
|
#ifdef ZgatewayPilight
|
|
PilighttoMQTT();
|
|
#endif
|
|
#ifdef ZgatewayBT
|
|
# ifdef ZmqttDiscovery
|
|
if (disc)
|
|
launchBTDiscovery();
|
|
# endif
|
|
# ifndef ESP32
|
|
if (BTtoMQTT())
|
|
Log.trace(F("BTtoMQTT OK" CR));
|
|
# else
|
|
emptyBTQueue();
|
|
# endif
|
|
#endif
|
|
#ifdef ZgatewaySRFB
|
|
SRFBtoMQTT();
|
|
#endif
|
|
#ifdef ZgatewayIR
|
|
IRtoMQTT();
|
|
#endif
|
|
#ifdef Zgateway2G
|
|
if (_2GtoMQTT())
|
|
Log.trace(F("2GtoMQTT OK" CR));
|
|
#endif
|
|
#ifdef ZgatewayRFM69
|
|
if (RFM69toMQTT())
|
|
Log.trace(F("RFM69toMQTT OK" CR));
|
|
#endif
|
|
#ifdef ZgatewayRS232
|
|
RS232toMQTT();
|
|
#endif
|
|
#ifdef ZactuatorFASTLED
|
|
FASTLEDLoop();
|
|
#endif
|
|
#ifdef ZactuatorPWM
|
|
PWMLoop();
|
|
#endif
|
|
#ifdef ZgatewayRTL_433
|
|
RTL_433Loop();
|
|
#endif
|
|
} else {
|
|
|
|
justReconnected = false;
|
|
connectMQTT();
|
|
}
|
|
} else {
|
|
|
|
justReconnected = false;
|
|
Log.warning(F("Network disconnected:" CR));
|
|
digitalWrite(LED_ERROR, LED_ERROR_ON);
|
|
delay(2000);
|
|
digitalWrite(LED_ERROR, !LED_ERROR_ON);
|
|
delay(2000);
|
|
#if defined(ESP8266) || defined(ESP32) && !defined(ESP32_ETHERNET)
|
|
# ifdef ESP32
|
|
WiFi.reconnect();
|
|
# endif
|
|
Log.warning(F("wifi" CR));
|
|
#else
|
|
Log.warning(F("ethernet" CR));
|
|
#endif
|
|
}
|
|
|
|
#if defined(ZboardM5STICKC) || defined(ZboardM5STICKCP) || defined(ZboardM5STACK) || defined(ZboardM5TOUGH)
|
|
loopM5();
|
|
#endif
|
|
|
|
|
|
#if defined(ZboardHELTEC)
|
|
loopHELTEC();
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned long uptime() {
|
|
static unsigned long lastUptime = 0;
|
|
static unsigned long uptimeAdd = 0;
|
|
unsigned long uptime = millis() / 1000 + uptimeAdd;
|
|
if (uptime < lastUptime) {
|
|
uptime += 4294967;
|
|
uptimeAdd += 4294967;
|
|
}
|
|
lastUptime = uptime;
|
|
return uptime;
|
|
}
|
|
|
|
#if defined(ESP8266) || defined(ESP32) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__)
|
|
void stateMeasures() {
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject SYSdata = jsonBuffer.to<JsonObject>();
|
|
SYSdata["uptime"] = uptime();
|
|
SYSdata["version"] = OMG_VERSION;
|
|
Log.trace(F("retrieving value of system characteristics Uptime (s):%u" CR), uptime());
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
uint32_t freeMem;
|
|
freeMem = ESP.getFreeHeap();
|
|
SYSdata["freemem"] = freeMem;
|
|
SYSdata["mqttport"] = mqtt_port;
|
|
SYSdata["mqttsecure"] = mqtt_secure;
|
|
# ifdef ESP32
|
|
SYSdata["freestack"] = uxTaskGetStackHighWaterMark(NULL);
|
|
# endif
|
|
# ifdef ESP32_ETHERNET
|
|
SYSdata["mac"] = (char*)ETH.macAddress().c_str();
|
|
SYSdata["ip"] = ip2CharArray(ETH.localIP());
|
|
ETH.fullDuplex() ? SYSdata["fd"] = (bool)"true" : SYSdata["fd"] = (bool)"false";
|
|
SYSdata["linkspeed"] = (int)ETH.linkSpeed();
|
|
# else
|
|
long rssi = WiFi.RSSI();
|
|
SYSdata["rssi"] = rssi;
|
|
String SSID = WiFi.SSID();
|
|
SYSdata["SSID"] = SSID;
|
|
String BSSID = WiFi.BSSIDstr();
|
|
SYSdata["BSSID"] = BSSID;
|
|
SYSdata["ip"] = ip2CharArray(WiFi.localIP());
|
|
String mac = WiFi.macAddress();
|
|
SYSdata["mac"] = (char*)mac.c_str();
|
|
# endif
|
|
# endif
|
|
# ifdef ZgatewayBT
|
|
# ifdef ESP32
|
|
SYSdata["lowpowermode"] = (int)lowpowermode;
|
|
SYSdata["btqblck"] = btQueueBlocked;
|
|
SYSdata["btqsum"] = btQueueLengthSum;
|
|
SYSdata["btqsnd"] = btQueueLengthCount;
|
|
SYSdata["btqavg"] = (btQueueLengthCount > 0 ? btQueueLengthSum / (float)btQueueLengthCount : 0);
|
|
# endif
|
|
SYSdata["interval"] = BTConfig.BLEinterval;
|
|
SYSdata["scanbcnct"] = BTConfig.BLEscanBeforeConnect;
|
|
SYSdata["scnct"] = scanCount;
|
|
# endif
|
|
# ifdef ZboardM5STACK
|
|
M5.Power.begin();
|
|
SYSdata["m5battlevel"] = (int8_t)M5.Power.getBatteryLevel();
|
|
SYSdata["m5ischarging"] = (bool)M5.Power.isCharging();
|
|
SYSdata["m5ischargefull"] = (bool)M5.Power.isChargeFull();
|
|
# endif
|
|
# if defined(ZboardM5STICKC) || defined(ZboardM5STICKCP) || defined(ZboardM5TOUGH)
|
|
M5.Axp.EnableCoulombcounter();
|
|
SYSdata["m5batvoltage"] = (float)M5.Axp.GetBatVoltage();
|
|
SYSdata["m5batcurrent"] = (float)M5.Axp.GetBatCurrent();
|
|
SYSdata["m5vinvoltage"] = (float)M5.Axp.GetVinVoltage();
|
|
SYSdata["m5vincurrent"] = (float)M5.Axp.GetVinCurrent();
|
|
SYSdata["m5vbusvoltage"] = (float)M5.Axp.GetVBusVoltage();
|
|
SYSdata["m5vbuscurrent"] = (float)M5.Axp.GetVBusCurrent();
|
|
SYSdata["m5tempaxp"] = (float)M5.Axp.GetTempInAXP192();
|
|
SYSdata["m5batpower"] = (float)M5.Axp.GetBatPower();
|
|
SYSdata["m5batchargecurrent"] = (float)M5.Axp.GetBatChargeCurrent();
|
|
SYSdata["m5apsvoltage"] = (float)M5.Axp.GetAPSVoltage();
|
|
# endif
|
|
# if defined(ZgatewayRF) || defined(ZgatewayPilight) || defined(ZgatewayRTL_433) || defined(ZgatewayRF2)
|
|
SYSdata["actRec"] = (int)activeReceiver;
|
|
# endif
|
|
# ifdef ZradioCC1101
|
|
SYSdata["mhz"] = (float)receiveMhz;
|
|
# endif
|
|
# if defined(ZgatewayRTL_433)
|
|
if (activeReceiver == ACTIVE_RTL) {
|
|
SYSdata["RTLminRssi"] = (int)getRTLMinimumRSSI();
|
|
SYSdata["RTLRssi"] = (int)getRTLCurrentRSSI();
|
|
SYSdata["RTLCnt"] = (int)getRTLMessageCount();
|
|
}
|
|
# endif
|
|
SYSdata["modules"] = modules;
|
|
pub(subjectSYStoMQTT, SYSdata);
|
|
}
|
|
#endif
|
|
|
|
#if defined(ZgatewayRF) || defined(ZgatewayIR) || defined(ZgatewaySRFB) || defined(ZgatewayWeatherStation)
|
|
|
|
|
|
|
|
void storeSignalValue(SIGNAL_SIZE_UL_ULL MQTTvalue) {
|
|
unsigned long now = millis();
|
|
|
|
int o = getMin();
|
|
Log.trace(F("Min ind: %d" CR), o);
|
|
|
|
receivedSignal[o].value = MQTTvalue;
|
|
receivedSignal[o].time = now;
|
|
|
|
|
|
Log.trace(F("store code : %u / %u" CR), (unsigned long)receivedSignal[o].value, receivedSignal[o].time);
|
|
Log.trace(F("Col: val/timestamp" CR));
|
|
for (int i = 0; i < struct_size; i++) {
|
|
Log.trace(F("mem code : %u / %u" CR), (unsigned long)receivedSignal[i].value, receivedSignal[i].time);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
int getMin() {
|
|
unsigned int minimum = receivedSignal[0].time;
|
|
int minindex = 0;
|
|
for (int i = 1; i < struct_size; i++) {
|
|
if (receivedSignal[i].time < minimum) {
|
|
minimum = receivedSignal[i].time;
|
|
minindex = i;
|
|
}
|
|
}
|
|
return minindex;
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isAduplicateSignal(SIGNAL_SIZE_UL_ULL value) {
|
|
Log.trace(F("isAdupl?" CR));
|
|
for (int i = 0; i < struct_size; i++) {
|
|
if (receivedSignal[i].value == value) {
|
|
unsigned long now = millis();
|
|
if (now - receivedSignal[i].time < time_avoid_duplicate) {
|
|
Log.notice(F("no pub. dupl" CR));
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
void receivingMQTT(char* topicOri, char* datacallback) {
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject jsondata = jsonBuffer.to<JsonObject>();
|
|
auto error = deserializeJson(jsonBuffer, datacallback);
|
|
if (error) {
|
|
Log.error(F("deserialize MQTT data failed: %s" CR), error.c_str());
|
|
return;
|
|
}
|
|
|
|
#if defined(ZgatewayRF) || defined(ZgatewayIR) || defined(ZgatewaySRFB) || defined(ZgatewayWeatherStation)
|
|
if (strstr(topicOri, subjectMultiGTWKey) != NULL) {
|
|
SIGNAL_SIZE_UL_ULL data = jsondata.isNull() ? STRTO_UL_ULL(datacallback, NULL, 10) : jsondata["value"];
|
|
if (data != 0 && !isAduplicateSignal(data)) {
|
|
storeSignalValue(data);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (!jsondata.isNull()) {
|
|
|
|
String buffer = "";
|
|
serializeJson(jsondata, buffer);
|
|
Log.notice(F("[ MQTT->OMG ]: %s" CR), buffer.c_str());
|
|
|
|
#ifdef ZgatewayPilight
|
|
MQTTtoPilight(topicOri, jsondata);
|
|
#endif
|
|
#ifdef ZgatewayRTL_433
|
|
MQTTtoRTL_433(topicOri, jsondata);
|
|
#endif
|
|
#if jsonReceiving
|
|
# ifdef ZgatewayLORA
|
|
MQTTtoLORA(topicOri, jsondata);
|
|
# endif
|
|
# ifdef ZgatewayRF
|
|
MQTTtoRF(topicOri, jsondata);
|
|
# endif
|
|
# ifdef ZgatewayRF2
|
|
MQTTtoRF2(topicOri, jsondata);
|
|
# endif
|
|
# ifdef Zgateway2G
|
|
MQTTto2G(topicOri, jsondata);
|
|
# endif
|
|
# ifdef ZgatewaySRFB
|
|
MQTTtoSRFB(topicOri, jsondata);
|
|
# endif
|
|
# ifdef ZgatewayIR
|
|
MQTTtoIR(topicOri, jsondata);
|
|
# endif
|
|
# ifdef ZgatewayRFM69
|
|
MQTTtoRFM69(topicOri, jsondata);
|
|
# endif
|
|
# ifdef ZgatewayBT
|
|
MQTTtoBT(topicOri, jsondata);
|
|
# endif
|
|
# ifdef ZactuatorFASTLED
|
|
MQTTtoFASTLED(topicOri, jsondata);
|
|
# endif
|
|
# ifdef ZactuatorPWM
|
|
MQTTtoPWM(topicOri, jsondata);
|
|
# endif
|
|
# if defined(ZboardM5STICKC) || defined(ZboardM5STICKCP) || defined(ZboardM5STACK) || defined(ZboardM5TOUGH)
|
|
MQTTtoM5(topicOri, jsondata);
|
|
# endif
|
|
# if defined(ZboardHELTEC)
|
|
MQTTtoHELTEC(topicOri, jsondata);
|
|
# endif
|
|
# ifdef ZactuatorONOFF
|
|
MQTTtoONOFF(topicOri, jsondata);
|
|
# endif
|
|
# ifdef ZactuatorSomfy
|
|
MQTTtoSomfy(topicOri, jsondata);
|
|
# endif
|
|
# ifdef ZgatewayRS232
|
|
MQTTtoRS232(topicOri, jsondata);
|
|
# endif
|
|
# ifdef MQTT_HTTPS_FW_UPDATE
|
|
MQTTHttpsFWUpdate(topicOri, jsondata);
|
|
# endif
|
|
#endif
|
|
digitalWrite(LED_SEND_RECEIVE, LED_SEND_RECEIVE_ON);
|
|
|
|
MQTTtoSYS(topicOri, jsondata);
|
|
} else {
|
|
#if simpleReceiving
|
|
# ifdef ZgatewayLORA
|
|
MQTTtoLORA(topicOri, datacallback);
|
|
# endif
|
|
# ifdef ZgatewayRF
|
|
MQTTtoRF(topicOri, datacallback);
|
|
# endif
|
|
# ifdef ZgatewayRF315
|
|
MQTTtoRF315(topicOri, datacallback);
|
|
# endif
|
|
# ifdef ZgatewayRF2
|
|
MQTTtoRF2(topicOri, datacallback);
|
|
# endif
|
|
# ifdef Zgateway2G
|
|
MQTTto2G(topicOri, datacallback);
|
|
# endif
|
|
# ifdef ZgatewaySRFB
|
|
MQTTtoSRFB(topicOri, datacallback);
|
|
# endif
|
|
# ifdef ZgatewayRFM69
|
|
MQTTtoRFM69(topicOri, datacallback);
|
|
# endif
|
|
# ifdef ZactuatorFASTLED
|
|
MQTTtoFASTLED(topicOri, datacallback);
|
|
# endif
|
|
#endif
|
|
#ifdef ZactuatorONOFF
|
|
MQTTtoONOFF(topicOri, datacallback);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#ifdef MQTT_HTTPS_FW_UPDATE
|
|
# ifdef ESP32
|
|
# include "zzHTTPUpdate.h"
|
|
# elif ESP8266
|
|
# include <ESP8266httpUpdate.h>
|
|
# endif
|
|
void MQTTHttpsFWUpdate(char* topicOri, JsonObject& HttpsFwUpdateData) {
|
|
if (strstr(topicOri, subjectFWUpdate) != NULL) {
|
|
const char* version = HttpsFwUpdateData["version"];
|
|
if (version && ((strlen(version) != strlen(OMG_VERSION)) || strcmp(version, OMG_VERSION) != 0)) {
|
|
const char* url = HttpsFwUpdateData["url"];
|
|
if (url) {
|
|
if (!strstr((url + (strlen(url) - 5)), ".bin")) {
|
|
Log.error(F("Invalid firmware extension" CR));
|
|
return;
|
|
}
|
|
} else {
|
|
Log.error(F("Invalid URL" CR));
|
|
return;
|
|
}
|
|
|
|
# if MQTT_HTTPS_FW_UPDATE_USE_PASSWORD > 0
|
|
const char* pwd = HttpsFwUpdateData["password"];
|
|
if (pwd) {
|
|
if (strcmp(pwd, ota_password) != 0) {
|
|
Log.error(F("Invalid OTA password" CR));
|
|
return;
|
|
}
|
|
} else {
|
|
Log.error(F("No password sent" CR));
|
|
return;
|
|
}
|
|
# endif
|
|
|
|
Log.warning(F("Starting firmware update" CR));
|
|
digitalWrite(LED_SEND_RECEIVE, LED_SEND_RECEIVE_ON);
|
|
digitalWrite(LED_ERROR, LED_ERROR_ON);
|
|
|
|
# if defined(ZgatewayBT) && defined(ESP32)
|
|
stopProcessing();
|
|
# endif
|
|
|
|
const char* ota_cert = HttpsFwUpdateData["server_cert"];
|
|
if (!ota_cert) {
|
|
if (ota_server_cert.length() > 0) {
|
|
Log.error(F("using stored cert" CR));
|
|
ota_cert = ota_server_cert.c_str();
|
|
} else {
|
|
Log.error(F("using config cert" CR));
|
|
ota_cert = OTAserver_cert;
|
|
}
|
|
}
|
|
|
|
t_httpUpdate_return result = HTTP_UPDATE_FAILED;
|
|
if (strstr(url, "http:")) {
|
|
WiFiClient update_client;
|
|
# ifdef ESP32
|
|
httpUpdate.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
|
result = httpUpdate.update(update_client, url);
|
|
# elif ESP8266
|
|
ESPhttpUpdate.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
|
result = ESPhttpUpdate.update(update_client, url);
|
|
# endif
|
|
|
|
} else {
|
|
WiFiClientSecure update_client;
|
|
if (mqtt_secure) {
|
|
client.disconnect();
|
|
update_client = *(WiFiClientSecure*)eClient;
|
|
} else {
|
|
configTime(0, 0, NTP_SERVER);
|
|
time_t now = time(nullptr);
|
|
uint8_t count = 0;
|
|
Log.trace(F("Waiting for NTP time sync" CR));
|
|
while ((now < 8 * 3600 * 2) && count++ < 60) {
|
|
delay(500);
|
|
now = time(nullptr);
|
|
}
|
|
|
|
if (count >= 60) {
|
|
Log.error(F("Unable to update - invalid time" CR));
|
|
# if defined(ZgatewayBT) && defined(ESP32)
|
|
startProcessing();
|
|
# endif
|
|
return;
|
|
}
|
|
}
|
|
|
|
# ifdef ESP32
|
|
update_client.setCACert(ota_cert);
|
|
update_client.setTimeout(12);
|
|
httpUpdate.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
|
httpUpdate.rebootOnUpdate(false);
|
|
result = httpUpdate.update(update_client, url);
|
|
# elif ESP8266
|
|
caCert.append(ota_cert);
|
|
update_client.setTrustAnchors(&caCert);
|
|
update_client.setTimeout(12000);
|
|
ESPhttpUpdate.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
|
ESPhttpUpdate.rebootOnUpdate(false);
|
|
result = ESPhttpUpdate.update(update_client, url);
|
|
# endif
|
|
}
|
|
|
|
switch (result) {
|
|
case HTTP_UPDATE_FAILED:
|
|
# ifdef ESP32
|
|
Log.error(F("HTTP_UPDATE_FAILED Error (%d): %s\n" CR), httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str());
|
|
# elif ESP8266
|
|
Log.error(F("HTTP_UPDATE_FAILED Error (%d): %s\n" CR), ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
|
|
# endif
|
|
break;
|
|
|
|
case HTTP_UPDATE_NO_UPDATES:
|
|
Log.notice(F("HTTP_UPDATE_NO_UPDATES" CR));
|
|
break;
|
|
|
|
case HTTP_UPDATE_OK:
|
|
Log.notice(F("HTTP_UPDATE_OK" CR));
|
|
ota_server_cert = ota_cert;
|
|
# ifndef ESPWifiManualSetup
|
|
saveMqttConfig();
|
|
# endif
|
|
# ifdef ESP32
|
|
ESP.restart();
|
|
# elif ESP8266
|
|
ESP.reset();
|
|
# endif
|
|
break;
|
|
}
|
|
|
|
digitalWrite(LED_SEND_RECEIVE, !LED_SEND_RECEIVE_ON);
|
|
digitalWrite(LED_ERROR, !LED_ERROR_ON);
|
|
|
|
# if defined(ZgatewayBT) && defined(ESP32)
|
|
startProcessing();
|
|
# endif
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void MQTTtoSYS(char* topicOri, JsonObject& SYSdata) {
|
|
if (cmpToMainTopic(topicOri, subjectMQTTtoSYSset)) {
|
|
Log.trace(F("MQTTtoSYS json" CR));
|
|
#if defined(ESP8266) || defined(ESP32)
|
|
if (SYSdata.containsKey("cmd")) {
|
|
const char* cmd = SYSdata["cmd"];
|
|
Log.notice(F("Command: %s" CR), cmd);
|
|
if (strstr(cmd, restartCmd) != NULL) {
|
|
# if defined(ESP8266)
|
|
ESP.reset();
|
|
# else
|
|
ESP.restart();
|
|
# endif
|
|
} else if (strstr(cmd, eraseCmd) != NULL) {
|
|
# ifndef ESPWifiManualSetup
|
|
setup_wifimanager(true);
|
|
# endif
|
|
} else if (strstr(cmd, statusCmd) != NULL) {
|
|
stateMeasures();
|
|
}
|
|
}
|
|
|
|
if (SYSdata.containsKey("wifi_ssid") && SYSdata.containsKey("wifi_pass")) {
|
|
# if defined(ZgatewayBT) && defined(ESP32)
|
|
stopProcessing();
|
|
# endif
|
|
String prev_ssid = WiFi.SSID();
|
|
String prev_pass = WiFi.psk();
|
|
client.disconnect();
|
|
WiFi.disconnect(true);
|
|
|
|
Log.warning(F("Attempting connection to new AP" CR));
|
|
WiFi.begin((const char*)SYSdata["wifi_ssid"], (const char*)SYSdata["wifi_pass"]);
|
|
WiFi.waitForConnectResult();
|
|
|
|
if (WiFi.status() != WL_CONNECTED) {
|
|
Log.error(F("Failed to connect to new AP; falling back" CR));
|
|
WiFi.disconnect(true);
|
|
WiFi.begin(prev_ssid.c_str(), prev_pass.c_str());
|
|
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
|
|
# if defined(ESP8266)
|
|
ESP.reset();
|
|
# else
|
|
ESP.restart();
|
|
# endif
|
|
}
|
|
}
|
|
# if defined(ZgatewayBT) && defined(ESP32)
|
|
startProcessing();
|
|
# endif
|
|
}
|
|
|
|
# ifdef MQTTsetMQTT
|
|
if (SYSdata.containsKey("mqtt_user") && SYSdata.containsKey("mqtt_pass")) {
|
|
bool update_server = false;
|
|
bool secure_connect = SYSdata["mqtt_secure"].as<bool>();
|
|
void* prev_client = nullptr;
|
|
bool use_ss_cert = SYSdata.containsKey("mqtt_cert_index");
|
|
uint8_t cert_index = mqtt_ss_index;
|
|
|
|
if (SYSdata.containsKey("mqtt_server") && SYSdata.containsKey("mqtt_port")) {
|
|
if (!SYSdata.containsKey("mqtt_secure")) {
|
|
Log.error(F("mqtt_server provided without mqtt_secure defined - ignoring command" CR));
|
|
return;
|
|
}
|
|
# if MQTT_SECURE_SELF_SIGNED
|
|
if (use_ss_cert) {
|
|
cert_index = SYSdata["mqtt_cert_index"].as<uint8_t>();
|
|
if (cert_index >= sizeof(certs_array) / sizeof(ss_certs)) {
|
|
Log.error(F("mqtt_cert_index invalid - ignoring command" CR));
|
|
return;
|
|
}
|
|
}
|
|
# endif
|
|
|
|
# if defined(ZgatewayBT) && defined(ESP32)
|
|
stopProcessing();
|
|
# endif
|
|
client.disconnect();
|
|
update_server = true;
|
|
if (secure_connect != mqtt_secure) {
|
|
prev_client = eClient;
|
|
if (!mqtt_secure) {
|
|
eClient = new WiFiClientSecure;
|
|
} else {
|
|
Log.warning(F("Switching to unsecure MQTT broker" CR));
|
|
eClient = new WiFiClient;
|
|
}
|
|
|
|
client.setClient(*(Client*)eClient);
|
|
}
|
|
|
|
if (secure_connect) {
|
|
setupTLS(use_ss_cert, cert_index);
|
|
}
|
|
|
|
client.setServer(SYSdata["mqtt_server"].as<const char*>(), SYSdata["mqtt_port"].as<unsigned int>());
|
|
} else {
|
|
# if defined(ZgatewayBT) && defined(ESP32)
|
|
stopProcessing();
|
|
# endif
|
|
client.disconnect();
|
|
}
|
|
|
|
String prev_user = mqtt_user;
|
|
String prev_pass = mqtt_pass;
|
|
strcpy(mqtt_user, SYSdata["mqtt_user"]);
|
|
strcpy(mqtt_pass, SYSdata["mqtt_pass"]);
|
|
|
|
connectMQTT();
|
|
|
|
if (client.connected()) {
|
|
if (update_server) {
|
|
strcpy(mqtt_server, SYSdata["mqtt_server"]);
|
|
strcpy(mqtt_port, SYSdata["mqtt_port"]);
|
|
mqtt_ss_index = cert_index;
|
|
if (prev_client != nullptr) {
|
|
mqtt_secure = !mqtt_secure;
|
|
delete prev_client;
|
|
}
|
|
}
|
|
# ifndef ESPWifiManualSetup
|
|
saveMqttConfig();
|
|
# endif
|
|
} else {
|
|
if (update_server) {
|
|
if (prev_client != nullptr) {
|
|
delete eClient;
|
|
eClient = prev_client;
|
|
client.setClient(*(Client*)eClient);
|
|
}
|
|
uint16_t port = strtol(mqtt_port, NULL, 10);
|
|
client.setServer(mqtt_server, port);
|
|
}
|
|
strcpy(mqtt_user, prev_user.c_str());
|
|
strcpy(mqtt_pass, prev_pass.c_str());
|
|
if (mqtt_secure) {
|
|
setupTLS(MQTT_SECURE_SELF_SIGNED, mqtt_ss_index);
|
|
}
|
|
connectMQTT();
|
|
}
|
|
# if defined(ZgatewayBT) && defined(ESP32)
|
|
startProcessing();
|
|
# endif
|
|
}
|
|
# endif
|
|
if (SYSdata.containsKey("mqtt_topic") || SYSdata.containsKey("gateway_name")) {
|
|
if (SYSdata.containsKey("mqtt_topic")) {
|
|
strncpy(mqtt_topic, SYSdata["mqtt_topic"], parameters_size);
|
|
}
|
|
if (SYSdata.containsKey("gateway_name")) {
|
|
strncpy(gateway_name, SYSdata["gateway_name"], parameters_size);
|
|
}
|
|
# ifndef ESPWifiManualSetup
|
|
saveMqttConfig();
|
|
# endif
|
|
client.disconnect();
|
|
}
|
|
#endif
|
|
|
|
#ifdef ZmqttDiscovery
|
|
if (SYSdata.containsKey("discovery")) {
|
|
if (SYSdata["discovery"].is<bool>()) {
|
|
disc = SYSdata["discovery"];
|
|
if (disc)
|
|
pubMqttDiscovery();
|
|
} else {
|
|
Log.error(F("Discovery command not a boolean" CR));
|
|
}
|
|
Log.notice(F("Discovery state: %T" CR), disc);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#if valueAsATopic && !defined(ZgatewayPilight)
|
|
# if defined(ESP32) || defined(ESP8266) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__)
|
|
String toString(uint64_t input) {
|
|
String result = "";
|
|
uint8_t base = 10;
|
|
|
|
do {
|
|
char c = input % base;
|
|
input /= base;
|
|
|
|
if (c < 10)
|
|
c += '0';
|
|
else
|
|
c += 'A' - 10;
|
|
result = c + result;
|
|
} while (input);
|
|
return result;
|
|
}
|
|
|
|
# else
|
|
|
|
String toString(uint32_t input) {
|
|
String result = String(input);
|
|
|
|
return result;
|
|
}
|
|
# endif
|
|
#endif
|
|
# 2151 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/main.ino"
|
|
void watchdogReboot(byte reason) {
|
|
Log.warning(F("Rebooting for reason code %d" CR), reason);
|
|
#if defined(ESP32)
|
|
ESP.restart();
|
|
#elif defined(ESP8266)
|
|
ESP.reset();
|
|
#else
|
|
#endif
|
|
}
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZactuatorFASTLED.ino"
|
|
# 23 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZactuatorFASTLED.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZactuatorFASTLED
|
|
|
|
# include <FastLED.h>
|
|
|
|
enum LEDState {
|
|
OFF,
|
|
FIRE,
|
|
GENERAL
|
|
};
|
|
LEDState currentLEDState;
|
|
long lastUpdate = 0;
|
|
long currentUpdate = 0;
|
|
CRGB leds[FASTLED_NUM_LEDS];
|
|
CRGB ledColorBlink[FASTLED_NUM_LEDS];
|
|
bool blinkLED[FASTLED_NUM_LEDS];
|
|
const long blinkInterval = 300;
|
|
const long fireUpdate = 10;
|
|
CRGBPalette16 gPal;
|
|
|
|
void setupFASTLED() {
|
|
Log.notice(F("FASTLED_DATA_GPIO: %d" CR), FASTLED_DATA_GPIO);
|
|
Log.notice(F("FASTLED_NUM_LEDS: %d" CR), FASTLED_NUM_LEDS);
|
|
Log.trace(F("ZactuatorFASTLED setup done " CR));
|
|
FastLED.addLeds<FASTLED_TYPE, FASTLED_DATA_GPIO>(leds, FASTLED_NUM_LEDS);
|
|
}
|
|
|
|
|
|
int animation_step(int duration, int steps) {
|
|
int currentStep = ((currentUpdate % duration) / ((float)duration)) * steps;
|
|
return currentStep;
|
|
}
|
|
|
|
|
|
int animation_step_count(int duration, int steps) {
|
|
long lastAnimationNumber = lastUpdate / duration;
|
|
long currentAnimationNumber = currentUpdate / duration;
|
|
int lastStep = ((lastUpdate % duration) / ((float)duration)) * steps;
|
|
int currentStep = ((currentUpdate % duration) / ((float)duration)) * steps;
|
|
|
|
return currentStep - lastStep + (currentAnimationNumber - lastAnimationNumber) * steps;
|
|
}
|
|
|
|
void FASTLEDLoop() {
|
|
lastUpdate = currentUpdate;
|
|
currentUpdate = millis();
|
|
|
|
if (currentLEDState == GENERAL) {
|
|
for (int i = 0; i < FASTLED_NUM_LEDS; i++) {
|
|
int count = animation_step_count(blinkInterval, 2);
|
|
int step = animation_step(blinkInterval, 2);
|
|
|
|
if (count > 0) {
|
|
if (blinkLED[i]) {
|
|
if (step == 0) {
|
|
leds[i] = ledColorBlink[i];
|
|
} else {
|
|
ledColorBlink[i] = leds[i];
|
|
leds[i] = CRGB::Black;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (currentLEDState == FIRE) {
|
|
int count = animation_step_count(fireUpdate, 1);
|
|
if (count > 0) {
|
|
|
|
Fire2012WithPalette();
|
|
}
|
|
}
|
|
FastLED.show();
|
|
}
|
|
|
|
boolean FASTLEDtoMQTT() {
|
|
return false;
|
|
}
|
|
# if jsonReceiving
|
|
void MQTTtoFASTLED(char* topicOri, JsonObject& jsonData) {
|
|
currentLEDState = GENERAL;
|
|
|
|
|
|
|
|
if (cmpToMainTopic(topicOri, subjectMQTTtoFASTLEDsetled)) {
|
|
Log.trace(F("MQTTtoFASTLED JSON analysis" CR));
|
|
int ledNr = jsonData["led"];
|
|
Log.notice(F("Led numero: %d" CR), ledNr);
|
|
const char* color = jsonData["hex"];
|
|
Log.notice(F("Color hex: %s" CR), color);
|
|
|
|
long number = (long)strtol(color, NULL, 16);
|
|
bool blink = jsonData["blink"];
|
|
if (ledNr <= FASTLED_NUM_LEDS) {
|
|
Log.notice(F("Blink: %d" CR), blink);
|
|
blinkLED[ledNr] = blink;
|
|
leds[ledNr] = number;
|
|
}
|
|
}
|
|
}
|
|
# endif
|
|
|
|
# if simpleReceiving
|
|
void MQTTtoFASTLED(char* topicOri, char* datacallback) {
|
|
Log.trace(F("MQTTtoFASTLED: " CR));
|
|
currentLEDState = GENERAL;
|
|
long number = 0;
|
|
if (cmpToMainTopic(topicOri, subjectMQTTtoFASTLED)) {
|
|
number = (long)strtol(&datacallback[1], NULL, 16);
|
|
Log.notice(F("Number: %l" CR), number);
|
|
for (int i = 0; i < FASTLED_NUM_LEDS; i++) {
|
|
leds[i] = number;
|
|
}
|
|
FastLED.show();
|
|
} else if (cmpToMainTopic(topicOri, subjectMQTTtoFASTLEDsetbrightness)) {
|
|
number = (long)strtol(&datacallback[1], NULL, 16);
|
|
Log.notice(F("Number: %l" CR), number);
|
|
FastLED.setBrightness(number);
|
|
FastLED.show();
|
|
} else if (cmpToMainTopic(topicOri, subjectMQTTtoFASTLEDsetanimation)) {
|
|
String payload = datacallback;
|
|
Log.notice(F("Datacallback: %s" CR), datacallback);
|
|
if (strstr(datacallback, "fire") != NULL) {
|
|
currentLEDState = FIRE;
|
|
gPal = HeatColors_p;
|
|
} else {
|
|
currentLEDState = OFF;
|
|
}
|
|
} else {
|
|
currentLEDState = OFF;
|
|
}
|
|
if (currentLEDState == OFF) {
|
|
for (int i = 0; i < FASTLED_NUM_LEDS; i++) {
|
|
leds[i] = CRGB::Black;
|
|
}
|
|
}
|
|
}
|
|
# endif
|
|
# 191 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZactuatorFASTLED.ino"
|
|
#define COOLING 55
|
|
|
|
|
|
|
|
|
|
#define SPARKING 120
|
|
bool gReverseDirection = false;
|
|
|
|
void Fire2012WithPalette() {
|
|
|
|
static byte heat[FASTLED_NUM_LEDS];
|
|
|
|
|
|
for (int i = 0; i < FASTLED_NUM_LEDS; i++) {
|
|
heat[i] = qsub8(heat[i], random8(0, ((COOLING * 10) / FASTLED_NUM_LEDS) + 2));
|
|
}
|
|
|
|
|
|
for (int k = FASTLED_NUM_LEDS - 1; k >= 2; k--) {
|
|
heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2]) / 3;
|
|
}
|
|
|
|
|
|
if (random8() < SPARKING) {
|
|
int y = random8(7);
|
|
heat[y] = qadd8(heat[y], random8(160, 255));
|
|
}
|
|
|
|
|
|
for (int j = 0; j < FASTLED_NUM_LEDS; j++) {
|
|
|
|
|
|
byte colorindex = scale8(heat[j], 240);
|
|
CRGB color = ColorFromPalette(gPal, colorindex);
|
|
int pixelnumber;
|
|
if (gReverseDirection) {
|
|
pixelnumber = (FASTLED_NUM_LEDS - 1) - j;
|
|
} else {
|
|
pixelnumber = j;
|
|
}
|
|
leds[pixelnumber] = color;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZactuatorONOFF.ino"
|
|
# 29 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZactuatorONOFF.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZactuatorONOFF
|
|
|
|
# if jsonReceiving
|
|
void MQTTtoONOFF(char* topicOri, JsonObject& ONOFFdata) {
|
|
if (cmpToMainTopic(topicOri, subjectMQTTtoONOFF)) {
|
|
Log.trace(F("MQTTtoONOFF json data analysis" CR));
|
|
int boolSWITCHTYPE = ONOFFdata["cmd"] | 99;
|
|
int gpio = ONOFFdata["gpio"] | ACTUATOR_ONOFF_GPIO;
|
|
if (boolSWITCHTYPE != 99) {
|
|
Log.notice(F("MQTTtoONOFF boolSWITCHTYPE ok: %d" CR), boolSWITCHTYPE);
|
|
Log.notice(F("GPIO number: %d" CR), gpio);
|
|
pinMode(gpio, OUTPUT);
|
|
digitalWrite(gpio, boolSWITCHTYPE);
|
|
|
|
pub(subjectGTWONOFFtoMQTT, ONOFFdata);
|
|
} else {
|
|
if (ONOFFdata["cmd"] == "high_pulse") {
|
|
Log.notice(F("MQTTtoONOFF high_pulse ok" CR));
|
|
Log.notice(F("GPIO number: %d" CR), gpio);
|
|
int pulselength = ONOFFdata["pulse_length"] | 500;
|
|
Log.notice(F("Pulse length: %d ms" CR), pulselength);
|
|
pinMode(gpio, OUTPUT);
|
|
digitalWrite(gpio, HIGH);
|
|
delay(pulselength);
|
|
digitalWrite(gpio, LOW);
|
|
} else if (ONOFFdata["cmd"] == "low_pulse") {
|
|
Log.notice(F("MQTTtoONOFF low_pulse ok" CR));
|
|
Log.notice(F("GPIO number: %d" CR), gpio);
|
|
int pulselength = ONOFFdata["pulse_length"] | 500;
|
|
Log.notice(F("Pulse length: %d ms" CR), pulselength);
|
|
pinMode(gpio, OUTPUT);
|
|
digitalWrite(gpio, LOW);
|
|
delay(pulselength);
|
|
digitalWrite(gpio, HIGH);
|
|
} else {
|
|
Log.error(F("MQTTtoONOFF failed json read" CR));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
# endif
|
|
|
|
# if simpleReceiving
|
|
void MQTTtoONOFF(char* topicOri, char* datacallback) {
|
|
if ((cmpToMainTopic(topicOri, subjectMQTTtoONOFF))) {
|
|
Log.trace(F("MQTTtoONOFF" CR));
|
|
char* endptr = NULL;
|
|
long gpio = strtol(datacallback, &endptr, 10);
|
|
if (datacallback == endptr)
|
|
gpio = ACTUATOR_ONOFF_GPIO;
|
|
|
|
Log.notice(F("GPIO number: %d" CR), gpio);
|
|
pinMode(gpio, OUTPUT);
|
|
|
|
bool ON = false;
|
|
if (strstr(topicOri, ONKey) != NULL)
|
|
ON = true;
|
|
if (strstr(topicOri, OFFKey) != NULL)
|
|
ON = false;
|
|
|
|
digitalWrite(gpio, ON);
|
|
|
|
char b = ON;
|
|
pub(subjectGTWONOFFtoMQTT, &b);
|
|
}
|
|
}
|
|
# endif
|
|
|
|
void ActuatorButtonTrigger() {
|
|
uint8_t level = !digitalRead(ACTUATOR_ONOFF_GPIO);
|
|
char* level_string = "ON";
|
|
if (level != ACTUATOR_ON) {
|
|
level_string = "OFF";
|
|
}
|
|
Log.trace(F("Actuator triggered %s by button" CR), level_string);
|
|
digitalWrite(ACTUATOR_ONOFF_GPIO, level);
|
|
pub(subjectGTWONOFFtoMQTT, level_string);
|
|
}
|
|
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZactuatorPWM.ino"
|
|
# 68 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZactuatorPWM.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZactuatorPWM
|
|
|
|
# include "config_PWM.h"
|
|
|
|
static long previousUpdateTime = 0;
|
|
static long currentUpdateTime = 0;
|
|
|
|
static const char* channelJsonKeys[] = PWM_CHANNEL_NAMES;
|
|
static const int channelPins[] = PWM_CHANNEL_PINS;
|
|
static const int kNumChannels = sizeof(channelPins) / sizeof(int);
|
|
|
|
|
|
static float currentValues[kNumChannels] = {};
|
|
static float fadeStartValues[kNumChannels] = {};
|
|
static float targetValues[kNumChannels] = {};
|
|
|
|
static long fadeStartUpdateTime[kNumChannels] = {};
|
|
static long fadeEndUpdateTime[kNumChannels] = {};
|
|
static bool fadeIsComplete = false;
|
|
|
|
|
|
static float calibrationMinLinear[kNumChannels];
|
|
static float calibrationMaxLinear[kNumChannels];
|
|
static float calibrationGamma[kNumChannels];
|
|
|
|
# if defined(ESP32)
|
|
|
|
|
|
static const int kNumDutyCycleBits = 16;
|
|
# elif defined(ESP8266)
|
|
|
|
|
|
static const int kNumDutyCycleBits = 10;
|
|
# else
|
|
|
|
|
|
|
|
static const int kNumDutyCycleBits = 8;
|
|
# endif
|
|
|
|
static const float kUNormToDutyCycle = (float)((1 << kNumDutyCycleBits) - 1);
|
|
|
|
void setupPWM() {
|
|
# 126 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZactuatorPWM.ino"
|
|
for (int i = 0; i < kNumChannels; ++i) {
|
|
# if defined(ESP32)
|
|
|
|
|
|
|
|
ledcSetup(i, 625.0, kNumDutyCycleBits);
|
|
ledcAttachPin(channelPins[i], i);
|
|
# endif
|
|
calibrationMinLinear[i] = 0.f;
|
|
calibrationMaxLinear[i] = 1.f;
|
|
calibrationGamma[i] = PWM_DEFAULT_GAMMA;
|
|
}
|
|
|
|
Log.trace(F("ZactuatorPWM setup done " CR));
|
|
}
|
|
|
|
|
|
|
|
static float perceptualToLinear(float perceptual, int channelIdx) {
|
|
return pow(perceptual, calibrationGamma[channelIdx]);
|
|
}
|
|
|
|
|
|
void PWMLoop() {
|
|
previousUpdateTime = currentUpdateTime;
|
|
currentUpdateTime = millis();
|
|
|
|
if (fadeIsComplete) {
|
|
return;
|
|
}
|
|
|
|
fadeIsComplete = true;
|
|
for (int i = 0; i < kNumChannels; ++i) {
|
|
|
|
long totalFadeDuration = fadeEndUpdateTime[i] - fadeStartUpdateTime[i];
|
|
float fadeLerpValue = 1.f;
|
|
if (totalFadeDuration > 0) {
|
|
fadeLerpValue = (float)(currentUpdateTime - fadeStartUpdateTime[i]) / (float)totalFadeDuration;
|
|
}
|
|
if (fadeLerpValue >= 1.f) {
|
|
currentValues[i] = targetValues[i];
|
|
} else {
|
|
currentValues[i] = ((targetValues[i] - fadeStartValues[i]) * fadeLerpValue) + fadeStartValues[i];
|
|
fadeIsComplete = false;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < kNumChannels; ++i) {
|
|
float linear = perceptualToLinear(currentValues[i], i);
|
|
|
|
|
|
if (linear > 0.f) {
|
|
|
|
linear = (linear * (calibrationMaxLinear[i] - calibrationMinLinear[i])) + calibrationMinLinear[i];
|
|
}
|
|
|
|
long dutyCycle = (long)(linear * kUNormToDutyCycle);
|
|
# if defined(ESP32)
|
|
ledcWrite(i, dutyCycle);
|
|
# else
|
|
analogWrite(channelPins[i], dutyCycle);
|
|
# endif
|
|
|
|
}
|
|
}
|
|
|
|
boolean PWMtoMQTT() {
|
|
return false;
|
|
}
|
|
|
|
# if jsonReceiving
|
|
void MQTTtoPWM(char* topicOri, JsonObject& jsonData) {
|
|
if (cmpToMainTopic(topicOri, subjectMQTTtoPWMset)) {
|
|
Log.trace(F("MQTTtoPWM JSON analysis" CR));
|
|
|
|
int modifiedChannelBits = 0;
|
|
for (int i = 0; i < kNumChannels; ++i) {
|
|
fadeStartValues[i] = currentValues[i];
|
|
JsonVariant value = jsonData[channelJsonKeys[i]];
|
|
if (!value.isNull()) {
|
|
float targetValue = value.as<float>();
|
|
targetValue = std::min(targetValue, 1.f);
|
|
targetValue = std::max(targetValue, 0.f);
|
|
targetValues[i] = targetValue;
|
|
|
|
|
|
fadeStartUpdateTime[i] = currentUpdateTime;
|
|
fadeEndUpdateTime[i] = currentUpdateTime;
|
|
|
|
modifiedChannelBits |= (1 << i);
|
|
}
|
|
}
|
|
|
|
JsonVariant fade = jsonData["fade"];
|
|
if (!fade.isNull()) {
|
|
|
|
long endUpdateTime = currentUpdateTime + (long)(fade.as<float>() * (1000.f));
|
|
|
|
for (int i = 0; i < kNumChannels; ++i) {
|
|
if (modifiedChannelBits & (1 << i)) {
|
|
fadeEndUpdateTime[i] = endUpdateTime;
|
|
}
|
|
}
|
|
}
|
|
fadeIsComplete = false;
|
|
} else if (cmpToMainTopic(topicOri, subjectMQTTtoPWMcalibrate)) {
|
|
|
|
for (int i = 0; i < kNumChannels; ++i) {
|
|
char key[64];
|
|
snprintf(key, sizeof(key), "gamma-%s", channelJsonKeys[i]);
|
|
JsonVariant value = jsonData[key];
|
|
if (!value.isNull()) {
|
|
float gamma = value.as<float>();
|
|
|
|
gamma = std::min(gamma, 4.f);
|
|
gamma = std::max(gamma, 0.5f);
|
|
calibrationGamma[i] = gamma;
|
|
}
|
|
snprintf(key, sizeof(key), "min-%s", channelJsonKeys[i]);
|
|
value = jsonData[key];
|
|
if (!value.isNull()) {
|
|
calibrationMinLinear[i] = perceptualToLinear(value.as<float>(), i);
|
|
}
|
|
snprintf(key, sizeof(key), "max-%s", channelJsonKeys[i]);
|
|
value = jsonData[key];
|
|
if (!value.isNull()) {
|
|
calibrationMaxLinear[i] = perceptualToLinear(value.as<float>(), i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
# endif
|
|
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZactuatorSomfy.ino"
|
|
# 24 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZactuatorSomfy.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZactuatorSomfy
|
|
|
|
# include <EEPROM.h>
|
|
# include <EEPROMRollingCodeStorage.h>
|
|
# include <SomfyRemote.h>
|
|
|
|
# ifdef ZradioCC1101
|
|
# include <ELECHOUSE_CC1101_SRC_DRV.h>
|
|
# endif
|
|
|
|
void setupSomfy() {
|
|
# ifdef ZradioCC1101
|
|
ELECHOUSE_cc1101.Init();
|
|
# endif
|
|
pinMode(RF_EMITTER_GPIO, OUTPUT);
|
|
digitalWrite(RF_EMITTER_GPIO, LOW);
|
|
|
|
# if defined(ESP32)
|
|
if (!EEPROM.begin(max(4, SOMFY_REMOTE_NUM * 2))) {
|
|
Log.error(F("failed to initialise EEPROM" CR));
|
|
}
|
|
# elif defined(ESP8266)
|
|
EEPROM.begin(max(4, SOMFY_REMOTE_NUM * 2));
|
|
# endif
|
|
|
|
Log.trace(F("ZactuatorSomfy setup done " CR));
|
|
}
|
|
|
|
# if jsonReceiving
|
|
void MQTTtoSomfy(char* topicOri, JsonObject& jsonData) {
|
|
if (cmpToMainTopic(topicOri, subjectMQTTtoSomfy)) {
|
|
# ifdef ZradioCC1101
|
|
ELECHOUSE_cc1101.SetTx(CC1101_FREQUENCY_SOMFY);
|
|
# endif
|
|
Log.trace(F("MQTTtoSomfy json data analysis" CR));
|
|
|
|
const int remoteIndex = jsonData["remote"];
|
|
if (remoteIndex >= SOMFY_REMOTE_NUM) {
|
|
Log.warning(F("ZactuatorSomfy remote does not exist" CR));
|
|
return;
|
|
}
|
|
const String commandData = jsonData["command"];
|
|
const Command command = getSomfyCommand(commandData);
|
|
|
|
const int repeat = jsonData["repeat"] | 4;
|
|
|
|
EEPROMRollingCodeStorage rollingCodeStorage(EEPROM_ADDRESS_START + remoteIndex * 2);
|
|
SomfyRemote somfyRemote(RF_EMITTER_GPIO, somfyRemotes[remoteIndex], &rollingCodeStorage);
|
|
somfyRemote.sendCommand(command, repeat);
|
|
# ifdef ZradioCC1101
|
|
ELECHOUSE_cc1101.SetRx(receiveMhz);
|
|
# endif
|
|
}
|
|
}
|
|
# endif
|
|
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZboardHeltec.ino"
|
|
# 31 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZboardHeltec.ino"
|
|
#include "User_config.h"
|
|
#if defined(ZboardHELTEC)
|
|
# include "ArduinoLog.h"
|
|
# include "config_HELTEC.h"
|
|
|
|
|
|
void logToLCD(bool display) {
|
|
display ? Log.begin(LOG_LEVEL_LCD, &Oled) : Log.begin(LOG_LEVEL, &Serial);
|
|
}
|
|
|
|
void setupHELTEC() {
|
|
Log.trace(F("Setup HELTEC Display" CR));
|
|
Oled.begin();
|
|
Log.notice(F("Setup HELTEC Display end" CR));
|
|
|
|
# if LOG_TO_LCD
|
|
Log.begin(LOG_LEVEL_LCD, &Oled);
|
|
# endif
|
|
}
|
|
|
|
void loopHELTEC() {
|
|
static int previousLogLevel;
|
|
int currentLogLevel = Log.getLastMsgLevel();
|
|
if (previousLogLevel != currentLogLevel && lowpowermode != 2) {
|
|
switch (currentLogLevel) {
|
|
case 1:
|
|
case 2:
|
|
|
|
|
|
|
|
break;
|
|
case 3:
|
|
|
|
|
|
|
|
break;
|
|
default:
|
|
|
|
|
|
Oled.fillScreen(WHITE);
|
|
Oled.drawLogo((int)OLED_WIDTH * 0.24, (int)(OLED_WIDTH / 2) - OLED_WIDTH * 0.2, (int)(OLED_HEIGHT / 2) + OLED_HEIGHT * 0.2, true, true, true, true, true, true);
|
|
break;
|
|
}
|
|
}
|
|
previousLogLevel = currentLogLevel;
|
|
}
|
|
|
|
void MQTTtoHELTEC(char* topicOri, JsonObject& HELTECdata) {
|
|
if (cmpToMainTopic(topicOri, subjectMQTTtoHELTECset)) {
|
|
Log.trace(F("MQTTtoHELTEC json set" CR));
|
|
|
|
if (HELTECdata.containsKey("log-lcd")) {
|
|
bool displayOnLCD = HELTECdata["log-lcd"];
|
|
Log.notice(F("Set lcd log: %T" CR), displayOnLCD);
|
|
logToLCD(displayOnLCD);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void heltecPrint(char* line1, char* line2, char* line3) {
|
|
Oled.println(line1);
|
|
Oled.println(line2);
|
|
Oled.println(line3);
|
|
delay(2000);
|
|
}
|
|
|
|
void heltecPrint(char* line1, char* line2) {
|
|
Oled.println(line1);
|
|
Oled.println(line2);
|
|
delay(2000);
|
|
}
|
|
|
|
void heltecPrint(char* line1) {
|
|
Oled.println(line1);
|
|
delay(2000);
|
|
}
|
|
|
|
|
|
|
|
OledSerial Oled(0);
|
|
OledSerial::OledSerial(int x) {
|
|
pinMode(RST_OLED, OUTPUT);
|
|
digitalWrite(RST_OLED, LOW);
|
|
delay(50);
|
|
digitalWrite(RST_OLED, HIGH);
|
|
|
|
# if defined(WIFI_Kit_32) || defined(WIFI_LoRa_32) || defined(WIFI_LoRa_32_V2)
|
|
display = new SSD1306Wire(0x3c, SDA_OLED, SCL_OLED, GEOMETRY_128_64);
|
|
# elif defined(Wireless_Stick)
|
|
display = new SSD1306Wire(0x3c, SDA_OLED, SCL_OLED, GEOMETRY_64_32);
|
|
# endif
|
|
}
|
|
|
|
void OledSerial::begin() {
|
|
|
|
display->init();
|
|
display->flipScreenVertically();
|
|
display->setFont(ArialMT_Plain_10);
|
|
|
|
display->setColor(WHITE);
|
|
display->fillRect(0, 0, OLED_WIDTH, OLED_HEIGHT);
|
|
display->display();
|
|
displayIntro(OLED_WIDTH * 0.24, (OLED_WIDTH / 2) - OLED_WIDTH * 0.2, (OLED_HEIGHT / 2) + OLED_HEIGHT * 0.2);
|
|
display->setLogBuffer(OLED_TEXT_ROWS, OLED_TEXT_BUFFER);
|
|
delay(1000);
|
|
}
|
|
|
|
|
|
|
|
int OledSerial::available(void) {
|
|
}
|
|
|
|
int OledSerial::peek(void) {
|
|
}
|
|
|
|
int OledSerial::read(void) {
|
|
}
|
|
|
|
void OledSerial::flush(void) {
|
|
}
|
|
|
|
void OledSerial::fillScreen(OLEDDISPLAY_COLOR color) {
|
|
display->clear();
|
|
display->setColor(color);
|
|
display->fillRect(0, 0, OLED_WIDTH, OLED_HEIGHT);
|
|
}
|
|
|
|
size_t OledSerial::write(uint8_t c) {
|
|
display->clear();
|
|
display->setColor(WHITE);
|
|
display->setFont(ArialMT_Plain_10);
|
|
|
|
display->write((char)c);
|
|
display->drawLogBuffer(0, 0);
|
|
display->display();
|
|
return 1;
|
|
}
|
|
|
|
size_t OledSerial::write(const uint8_t* buffer, size_t size) {
|
|
display->clear();
|
|
display->setColor(WHITE);
|
|
display->setFont(ArialMT_Plain_10);
|
|
while (size) {
|
|
display->write((char)*buffer++);
|
|
size--;
|
|
}
|
|
display->drawLogBuffer(0, 0);
|
|
display->display();
|
|
return size;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void OledSerial::displayIntro(int scale, int displayWidth, int displayHeight) {
|
|
drawLogo(scale, displayWidth, displayHeight, false, true, false, false, false, false);
|
|
drawLogo(scale, displayWidth, displayHeight, false, false, true, false, false, false);
|
|
drawLogo(scale, displayWidth, displayHeight, false, true, true, true, false, false);
|
|
drawLogo(scale, displayWidth, displayHeight, false, true, true, false, true, false);
|
|
drawLogo(scale, displayWidth, displayHeight, true, true, true, true, true, false);
|
|
drawLogo(scale, displayWidth, displayHeight, true, true, true, true, true, true);
|
|
}
|
|
|
|
void OledSerial::drawLogo(int logoSize, int circle1X, int circle1Y, bool circle1, bool circle2, bool circle3, bool line1, bool line2, bool name) {
|
|
int circle1T = logoSize / 15;
|
|
int circle2T = logoSize / 25;
|
|
int circle3T = logoSize / 30;
|
|
|
|
int circle3Y = circle1Y - (logoSize * 1.2);
|
|
int circle3X = circle1X - (logoSize * 0.13);
|
|
int circle2X = circle1X - (logoSize * 1.05);
|
|
int circle2Y = circle1Y - (logoSize * 0.8);
|
|
|
|
if (line1) {
|
|
display->setColor(BLACK);
|
|
display->drawLine(circle1X - 2, circle1Y, circle2X - 2, circle2Y);
|
|
display->drawLine(circle1X - 1, circle1Y, circle2X - 1, circle2Y);
|
|
display->drawLine(circle1X, circle1Y, circle2X, circle2Y);
|
|
display->drawLine(circle1X + 1, circle1Y, circle2X + 1, circle2Y);
|
|
display->drawLine(circle1X + 2, circle1Y, circle2X + 2, circle2Y);
|
|
display->setColor(WHITE);
|
|
display->fillCircle(circle3X, circle3Y, logoSize / 4 - circle3T * 2);
|
|
}
|
|
if (line2) {
|
|
display->setColor(BLACK);
|
|
display->drawLine(circle1X - 2, circle1Y, circle3X - 2, circle3Y);
|
|
display->drawLine(circle1X - 1, circle1Y, circle3X - 1, circle3Y);
|
|
display->drawLine(circle1X, circle1Y, circle3X, circle3Y);
|
|
display->drawLine(circle1X + 1, circle1Y, circle3X + 1, circle3Y);
|
|
display->setColor(WHITE);
|
|
display->fillCircle(circle2X, circle2Y, logoSize / 3 - circle2T * 2);
|
|
}
|
|
if (circle1) {
|
|
display->setColor(WHITE);
|
|
display->fillCircle(circle1X, circle1Y, logoSize / 2);
|
|
display->setColor(BLACK);
|
|
display->fillCircle(circle1X, circle1Y, logoSize / 2 - circle1T);
|
|
display->setColor(WHITE);
|
|
display->fillCircle(circle1X, circle1Y, logoSize / 2 - circle1T * 2);
|
|
}
|
|
if (circle2) {
|
|
display->setColor(WHITE);
|
|
display->fillCircle(circle2X, circle2Y, logoSize / 3);
|
|
display->setColor(BLACK);
|
|
display->fillCircle(circle2X, circle2Y, logoSize / 3 - circle2T);
|
|
display->setColor(WHITE);
|
|
display->fillCircle(circle2X, circle2Y, logoSize / 3 - circle2T * 2);
|
|
}
|
|
if (circle3) {
|
|
display->setColor(WHITE);
|
|
display->fillCircle(circle3X, circle3Y, logoSize / 4);
|
|
display->setColor(BLACK);
|
|
display->fillCircle(circle3X, circle3Y, logoSize / 4 - circle3T);
|
|
display->setColor(WHITE);
|
|
display->fillCircle(circle3X, circle3Y, logoSize / 4 - circle3T * 2);
|
|
}
|
|
if (name) {
|
|
display->setColor(BLACK);
|
|
display->drawString(circle1X + (circle1X * 0.27), circle1Y, "penMQTTGateway");
|
|
}
|
|
display->display();
|
|
delay(50);
|
|
}
|
|
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZboardM5.ino"
|
|
# 29 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZboardM5.ino"
|
|
#include "User_config.h"
|
|
|
|
#if defined(ZboardM5STICKC) || defined(ZboardM5STICKCP) || defined(ZboardM5STACK) || defined(ZboardM5TOUGH)
|
|
# ifdef ZboardM5STICKC
|
|
# include <M5StickC.h>
|
|
# endif
|
|
# ifdef ZboardM5STICKCP
|
|
# include <M5StickCPlus.h>
|
|
# endif
|
|
# ifdef ZboardM5STACK
|
|
# include <M5Stack.h>
|
|
# endif
|
|
# ifdef ZboardM5TOUGH
|
|
# include <M5Tough.h>
|
|
# endif
|
|
void logToLCD(bool display) {
|
|
display ? Log.begin(LOG_LEVEL_LCD, &M5.Lcd) : Log.begin(LOG_LEVEL, &Serial);
|
|
}
|
|
|
|
void setBrightness(int brightness) {
|
|
# if defined(ZboardM5STACK)
|
|
M5.Lcd.setBrightness(brightness * 2);
|
|
# endif
|
|
# if defined(ZboardM5STICKC) || defined(ZboardM5STICKCP) || defined(ZboardM5TOUGH)
|
|
(!brightness) ? M5.Axp.ScreenBreath(0) : M5.Axp.ScreenBreath(7 + (int)brightness * 0.08);
|
|
# endif
|
|
}
|
|
|
|
void setupM5() {
|
|
Log.notice(F("Setup M5" CR));
|
|
pinMode(SLEEP_BUTTON, INPUT);
|
|
|
|
|
|
|
|
Log.notice(F("Low power set to: %d" CR), lowpowermode);
|
|
switch (lowpowermode)
|
|
{
|
|
case 0:
|
|
wakeScreen(NORMAL_LCD_BRIGHTNESS);
|
|
M5.Lcd.fillScreen(WHITE);
|
|
displayIntro(M5.Lcd.width() * 0.25, (M5.Lcd.width() / 2) + M5.Lcd.width() * 0.12, (M5.Lcd.height() / 2) + M5.Lcd.height() * 0.2);
|
|
# if LOG_TO_LCD
|
|
Log.begin(LOG_LEVEL_LCD, &M5.Lcd);
|
|
# endif
|
|
break;
|
|
case 1:
|
|
wakeScreen(SLEEP_LCD_BRIGHTNESS);
|
|
M5.Lcd.fillScreen(WHITE);
|
|
# if LOG_TO_LCD
|
|
Log.begin(LOG_LEVEL_LCD, &M5.Lcd);
|
|
# endif
|
|
break;
|
|
case 2:
|
|
M5.begin(false, false, false);
|
|
break;
|
|
}
|
|
Log.notice(F("Setup M5 end" CR));
|
|
}
|
|
|
|
void sleepScreen() {
|
|
Log.trace(F("Screen going to sleep" CR));
|
|
# if defined(ZboardM5STACK)
|
|
M5.begin(false, false, false);
|
|
# endif
|
|
# if defined(ZboardM5STICKC) || defined(ZboardM5STICKCP) || defined(ZboardM5TOUGH)
|
|
M5.Axp.ScreenBreath(0);
|
|
M5.Axp.SetLDO2(false);
|
|
# endif
|
|
}
|
|
|
|
void wakeScreen(int brightness) {
|
|
Log.trace(F("Screen wake up" CR));
|
|
M5.begin();
|
|
M5.Lcd.setCursor(0, 0, (M5.Lcd.height() > 200) ? 4 : 2);
|
|
M5.Lcd.setTextSize(1);
|
|
M5.Lcd.setRotation(1);
|
|
setBrightness(brightness);
|
|
}
|
|
|
|
void loopM5() {
|
|
static int previousBtnState;
|
|
int currentBtnState = digitalRead(SLEEP_BUTTON);
|
|
if (currentBtnState != previousBtnState && currentBtnState == 0) {
|
|
int newlowpowermode = lowpowermode;
|
|
(lowpowermode == 2) ? newlowpowermode = 0 : newlowpowermode = newlowpowermode + 1;
|
|
changelowpowermode(newlowpowermode);
|
|
}
|
|
previousBtnState = currentBtnState;
|
|
static int previousLogLevel;
|
|
int currentLogLevel = Log.getLastMsgLevel();
|
|
if (previousLogLevel != currentLogLevel && lowpowermode != 2) {
|
|
switch (currentLogLevel) {
|
|
case 1:
|
|
case 2:
|
|
wakeScreen(NORMAL_LCD_BRIGHTNESS);
|
|
M5.Lcd.fillScreen(TFT_RED);
|
|
M5.Lcd.setTextColor(TFT_BLACK, TFT_RED);
|
|
break;
|
|
case 3:
|
|
wakeScreen(NORMAL_LCD_BRIGHTNESS);
|
|
M5.Lcd.fillScreen(TFT_ORANGE);
|
|
M5.Lcd.setTextColor(TFT_BLACK, TFT_ORANGE);
|
|
break;
|
|
default:
|
|
wakeScreen(SLEEP_LCD_BRIGHTNESS);
|
|
M5.Lcd.fillScreen(TFT_WHITE);
|
|
drawLogo(M5.Lcd.width() * 0.1875, (M5.Lcd.width() / 2) - M5.Lcd.width() * 0.24, M5.Lcd.height() * 0.5, true, true, true, true, true, true);
|
|
break;
|
|
}
|
|
}
|
|
previousLogLevel = currentLogLevel;
|
|
}
|
|
|
|
void MQTTtoM5(char* topicOri, JsonObject& M5data) {
|
|
if (cmpToMainTopic(topicOri, subjectMQTTtoM5set)) {
|
|
Log.trace(F("MQTTtoM5 json set" CR));
|
|
|
|
if (M5data.containsKey("log-lcd")) {
|
|
bool displayOnLCD = M5data["log-lcd"];
|
|
Log.notice(F("Set lcd log: %T" CR), displayOnLCD);
|
|
logToLCD(displayOnLCD);
|
|
}
|
|
}
|
|
}
|
|
|
|
void displayIntro(int i, int X, int Y) {
|
|
Log.trace(F("Intro display on screen" CR));
|
|
drawLogo(i, X, Y, false, true, false, false, false, false);
|
|
delay(50);
|
|
drawLogo(i, X, Y, false, false, true, false, false, false);
|
|
delay(50);
|
|
drawLogo(i, X, Y, false, true, false, false, false, false);
|
|
delay(50);
|
|
drawLogo(i, X, Y, false, true, true, false, false, false);
|
|
delay(50);
|
|
drawLogo(i, X, Y, false, true, true, true, false, false);
|
|
delay(50);
|
|
drawLogo(i, X, Y, false, true, true, false, true, false);
|
|
delay(50);
|
|
drawLogo(i, X, Y, false, true, true, true, true, false);
|
|
delay(50);
|
|
drawLogo(i, X, Y, true, true, true, true, true, false);
|
|
}
|
|
|
|
void drawLogo(int logoSize, int circle1X, int circle1Y, bool circle1, bool circle2, bool circle3, bool line1, bool line2, bool name) {
|
|
int circle1T = logoSize / 15;
|
|
int circle2T = logoSize / 25;
|
|
int circle3T = logoSize / 30;
|
|
|
|
int circle3Y = circle1Y - (logoSize * 1.2);
|
|
int circle3X = circle1X - (logoSize * 0.13);
|
|
int circle2X = circle1X - (logoSize * 1.05);
|
|
int circle2Y = circle1Y - (logoSize * 0.8);
|
|
|
|
if (line1) {
|
|
M5.Lcd.drawLine(circle1X - 2, circle1Y, circle2X - 2, circle2Y, BLUE);
|
|
M5.Lcd.drawLine(circle1X - 1, circle1Y, circle2X - 1, circle2Y, BLUE);
|
|
M5.Lcd.drawLine(circle1X, circle1Y, circle2X, circle2Y, BLUE);
|
|
M5.Lcd.drawLine(circle1X + 1, circle1Y, circle2X + 1, circle2Y, BLUE);
|
|
M5.Lcd.drawLine(circle1X + 2, circle1Y, circle2X + 2, circle2Y, BLUE);
|
|
M5.Lcd.fillCircle(circle3X, circle3Y, logoSize / 4 - circle3T * 2, WHITE);
|
|
}
|
|
if (line2) {
|
|
M5.Lcd.drawLine(circle1X - 2, circle1Y, circle3X - 2, circle3Y, BLUE);
|
|
M5.Lcd.drawLine(circle1X - 1, circle1Y, circle3X - 1, circle3Y, BLUE);
|
|
M5.Lcd.drawLine(circle1X, circle1Y, circle3X, circle3Y, BLUE);
|
|
M5.Lcd.drawLine(circle1X + 1, circle1Y, circle3X + 1, circle3Y, BLUE);
|
|
M5.Lcd.fillCircle(circle2X, circle2Y, logoSize / 3 - circle2T * 2, WHITE);
|
|
}
|
|
M5.Lcd.fillCircle(circle1X, circle1Y, logoSize / 2 - circle1T * 2, WHITE);
|
|
if (circle1) {
|
|
M5.Lcd.fillCircle(circle1X, circle1Y, logoSize / 2, WHITE);
|
|
M5.Lcd.fillCircle(circle1X, circle1Y, logoSize / 2 - circle1T, TFT_GREEN);
|
|
M5.Lcd.fillCircle(circle1X, circle1Y, logoSize / 2 - circle1T * 2, WHITE);
|
|
}
|
|
if (circle2) {
|
|
M5.Lcd.fillCircle(circle2X, circle2Y, logoSize / 3, WHITE);
|
|
M5.Lcd.fillCircle(circle2X, circle2Y, logoSize / 3 - circle2T, TFT_ORANGE);
|
|
M5.Lcd.fillCircle(circle2X, circle2Y, logoSize / 3 - circle2T * 2, WHITE);
|
|
}
|
|
if (circle3) {
|
|
M5.Lcd.fillCircle(circle3X, circle3Y, logoSize / 4, WHITE);
|
|
M5.Lcd.fillCircle(circle3X, circle3Y, logoSize / 4 - circle3T, TFT_PINK);
|
|
M5.Lcd.fillCircle(circle3X, circle3Y, logoSize / 4 - circle3T * 2, WHITE);
|
|
}
|
|
if (name) {
|
|
M5.Lcd.setTextColor(BLUE);
|
|
M5.Lcd.drawString("penMQTTGateway", circle1X + (circle1X * 0.27), circle1Y, (M5.Lcd.height() > 200) ? 4 : 2);
|
|
}
|
|
}
|
|
|
|
void M5Print(char* line1, char* line2, char* line3) {
|
|
if (lowpowermode == 2) digitalWrite(LED_INFO, LED_INFO_ON);
|
|
wakeScreen(NORMAL_LCD_BRIGHTNESS);
|
|
M5.Lcd.fillScreen(TFT_WHITE);
|
|
drawLogo(M5.Lcd.width() * 0.1875, (M5.Lcd.width() / 2) - M5.Lcd.width() * 0.24, M5.Lcd.height() * 0.5, true, true, true, true, true, true);
|
|
M5.Lcd.setTextColor(BLUE);
|
|
M5.Lcd.drawString(line1, 5, M5.Lcd.height() * 0.7, 1);
|
|
M5.Lcd.drawString(line2, 5, M5.Lcd.height() * 0.8, 1);
|
|
M5.Lcd.drawString(line3, 5, M5.Lcd.height() * 0.9, 1);
|
|
delay(2000);
|
|
digitalWrite(LED_INFO, !LED_INFO_ON);
|
|
}
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/Zgateway2G.ino"
|
|
# 28 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/Zgateway2G.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef Zgateway2G
|
|
|
|
# include <A6lib.h>
|
|
# include <ArduinoJson.h>
|
|
|
|
|
|
A6lib A6l(_2G_TX_GPIO, _2G_RX_GPIO);
|
|
|
|
int unreadSMSLocs[50] = {0};
|
|
int unreadSMSNum = 0;
|
|
SMSmessage sms;
|
|
|
|
void setup2G() {
|
|
Log.notice(F("_2G_TX_GPIO: %d " CR), _2G_TX_GPIO);
|
|
Log.notice(F("_2G_RX_GPIO: %d " CR), _2G_RX_GPIO);
|
|
setupGSM(false);
|
|
Log.trace(F("Zgateway2G setup done " CR));
|
|
}
|
|
|
|
void setupGSM(bool deleteSMS) {
|
|
Log.trace(F("Init 2G module: %d" CR), _2G_PWR_GPIO);
|
|
delay(1000);
|
|
|
|
A6l.powerCycle(_2G_PWR_GPIO);
|
|
Log.notice(F("waiting for network connection at bd: %d" CR), _2G_MODULE_BAUDRATE);
|
|
A6l.blockUntilReady(_2G_MODULE_BAUDRATE);
|
|
Log.notice(F("A6/A7 gsm ready" CR));
|
|
signalStrengthAnalysis();
|
|
delay(1000);
|
|
|
|
if (deleteSMS) {
|
|
if (A6l.deleteSMS(1, 4) == A6_OK) {
|
|
Log.notice(F("delete SMS OK" CR));
|
|
} else {
|
|
Log.error(F("delete SMS KO" CR));
|
|
}
|
|
}
|
|
}
|
|
|
|
void signalStrengthAnalysis() {
|
|
int signalStrength = 0;
|
|
signalStrength = A6l.getSignalStrength();
|
|
Log.trace(F("Signal strength: %d" CR), signalStrength);
|
|
if (signalStrength < _2G_MIN_SIGNAL || signalStrength > _2G_MAX_SIGNAL) {
|
|
Log.trace(F("Signal too low restart the module" CR));
|
|
setupGSM(false);
|
|
}
|
|
}
|
|
|
|
bool _2GtoMQTT() {
|
|
|
|
unreadSMSNum = A6l.getUnreadSMSLocs(unreadSMSLocs, 512);
|
|
Log.trace(F("Creating SMS buffer" CR));
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject SMSdata = jsonBuffer.to<JsonObject>();
|
|
for (int i = 0; i < unreadSMSNum; i++) {
|
|
Log.notice(F("New message at index: %d" CR), unreadSMSNum);
|
|
sms = A6l.readSMS(unreadSMSLocs[i]);
|
|
SMSdata["message"] = (const char*)sms.message.c_str();
|
|
SMSdata["date"] = (const char*)sms.date.c_str();
|
|
SMSdata["phone"] = (const char*)sms.number.c_str();
|
|
A6l.deleteSMS(unreadSMSLocs[i]);
|
|
Log.trace(F("Adv data 2GtoMQTT" CR));
|
|
pub(subject2GtoMQTT, SMSdata);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
# if simpleReceiving
|
|
void MQTTto2G(char* topicOri, char* datacallback) {
|
|
String data = datacallback;
|
|
String topic = topicOri;
|
|
|
|
if (cmpToMainTopic(topicOri, subjectMQTTto2G)) {
|
|
Log.trace(F("MQTTto2G data analysis" CR));
|
|
|
|
String phone_number = "";
|
|
int pos0 = topic.lastIndexOf(_2GPhoneKey);
|
|
if (pos0 != -1) {
|
|
pos0 = pos0 + strlen(_2GPhoneKey);
|
|
phone_number = topic.substring(pos0);
|
|
Log.notice(F("MQTTto2G phone: %s" CR), (char*)phone_number.c_str());
|
|
Log.notice(F("MQTTto2G sms: %s" CR), (char*)data.c_str());
|
|
if (A6l.sendSMS(phone_number, data) == A6_OK) {
|
|
Log.notice(F("SMS OK" CR));
|
|
|
|
pub(subjectGTW2GtoMQTT, "SMS OK");
|
|
} else {
|
|
Log.error(F("SMS KO" CR));
|
|
|
|
pub(subjectGTW2GtoMQTT, "SMS KO");
|
|
}
|
|
} else {
|
|
Log.error(F("MQTTto2G Fail reading phone number" CR));
|
|
}
|
|
}
|
|
}
|
|
# endif
|
|
|
|
# if jsonReceiving
|
|
void MQTTto2G(char* topicOri, JsonObject& SMSdata) {
|
|
if (cmpToMainTopic(topicOri, subjectMQTTto2G)) {
|
|
const char* sms = SMSdata["message"];
|
|
const char* phone = SMSdata["phone"];
|
|
Log.trace(F("MQTTto2G json data analysis" CR));
|
|
if (sms && phone) {
|
|
Log.notice(F("MQTTto2G phone: %s" CR), phone);
|
|
Log.notice(F("MQTTto2G sms: %s" CR), sms);
|
|
if (A6l.sendSMS(String(phone), String(sms)) == A6_OK) {
|
|
Log.notice(F("SMS OK" CR));
|
|
|
|
pub(subjectGTW2GtoMQTT, "SMS OK");
|
|
} else {
|
|
Log.error(F("SMS KO" CR));
|
|
pub(subjectGTW2GtoMQTT, "SMS KO");
|
|
}
|
|
} else {
|
|
Log.error(F("MQTTto2G failed json read" CR));
|
|
}
|
|
}
|
|
}
|
|
# endif
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayBLEConnect.ino"
|
|
#ifdef ESP32
|
|
# include "User_config.h"
|
|
# ifdef ZgatewayBT
|
|
# include "ArduinoJson.h"
|
|
# include "ArduinoLog.h"
|
|
# include "ZgatewayBLEConnect.h"
|
|
|
|
#define convertTemp_CtoF(c) ((c * 1.8) + 32)
|
|
|
|
extern bool ProcessLock;
|
|
extern std::vector<BLEdevice*> devices;
|
|
|
|
NimBLERemoteCharacteristic* zBLEConnect::getCharacteristic(const NimBLEUUID& service,
|
|
const NimBLEUUID& characteristic) {
|
|
BLERemoteCharacteristic* pRemoteCharacteristic = nullptr;
|
|
if (!m_pClient) {
|
|
Log.error(F("No BLE client" CR));
|
|
} else if (!m_pClient->isConnected() && !m_pClient->connect()) {
|
|
Log.error(F("Connect to: %s failed" CR), m_pClient->getPeerAddress().toString().c_str());
|
|
} else {
|
|
BLERemoteService* pRemoteService = m_pClient->getService(service);
|
|
if (!pRemoteService) {
|
|
Log.notice(F("Failed to find service UUID: %s" CR), service.toString().c_str());
|
|
} else {
|
|
Log.trace(F("Found service: %s" CR), service.toString().c_str());
|
|
Log.trace(F("Client isConnected, freeHeap: %d" CR), ESP.getFreeHeap());
|
|
pRemoteCharacteristic = pRemoteService->getCharacteristic(characteristic);
|
|
if (!pRemoteCharacteristic) {
|
|
Log.notice(F("Failed to find characteristic UUID: %s" CR), characteristic.toString().c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
return pRemoteCharacteristic;
|
|
}
|
|
|
|
bool zBLEConnect::writeData(BLEAction* action) {
|
|
NimBLERemoteCharacteristic* pChar = getCharacteristic(action->service, action->characteristic);
|
|
if (pChar && (pChar->canWrite() || pChar->canWriteNoResponse())) {
|
|
switch (action->value_type) {
|
|
case BLE_VAL_HEX: {
|
|
int len = action->value.length();
|
|
if (len % 2) {
|
|
Log.error(F("Invalid HEX value length" CR));
|
|
return false;
|
|
}
|
|
|
|
std::vector<uint8_t> buf;
|
|
for (auto i = 0; i < len; i += 2) {
|
|
std::string temp = action->value.substr(i, 2);
|
|
buf.push_back((uint8_t)strtoul(temp.c_str(), nullptr, 16));
|
|
}
|
|
return pChar->writeValue((const uint8_t*)&buf[0], buf.size(), !pChar->canWriteNoResponse());
|
|
}
|
|
case BLE_VAL_INT:
|
|
return pChar->writeValue(strtol(action->value.c_str(), nullptr, 0), !pChar->canWriteNoResponse());
|
|
case BLE_VAL_FLOAT:
|
|
return pChar->writeValue(strtod(action->value.c_str(), nullptr), !pChar->canWriteNoResponse());
|
|
default:
|
|
return pChar->writeValue(action->value, !pChar->canWriteNoResponse());
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool zBLEConnect::readData(BLEAction* action) {
|
|
NimBLERemoteCharacteristic* pChar = getCharacteristic(action->service, action->characteristic);
|
|
|
|
if (pChar && pChar->canRead()) {
|
|
action->value = pChar->readValue();
|
|
if (action->value != "") {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool zBLEConnect::processActions(std::vector<BLEAction>& actions) {
|
|
bool result = false;
|
|
if (actions.size() > 0) {
|
|
for (auto& it : actions) {
|
|
if (NimBLEAddress(it.addr) == m_pClient->getPeerAddress()) {
|
|
JsonObject BLEresult = getBTJsonObject();
|
|
BLEresult["id"] = it.addr;
|
|
BLEresult["service"] = it.service.toString();
|
|
BLEresult["characteristic"] = it.characteristic.toString();
|
|
|
|
if (it.write) {
|
|
Log.trace(F("processing BLE write" CR));
|
|
BLEresult["write"] = it.value;
|
|
result = writeData(&it);
|
|
} else {
|
|
Log.trace(F("processing BLE read" CR));
|
|
result = readData(&it);
|
|
if (result) {
|
|
switch (it.value_type) {
|
|
case BLE_VAL_HEX: {
|
|
char* pHex = NimBLEUtils::buildHexData(nullptr, (uint8_t*)it.value.c_str(), it.value.length());
|
|
BLEresult["read"] = pHex;
|
|
free(pHex);
|
|
break;
|
|
}
|
|
case BLE_VAL_INT: {
|
|
int ival = *(int*)it.value.data();
|
|
BLEresult["read"] = ival;
|
|
break;
|
|
}
|
|
case BLE_VAL_FLOAT: {
|
|
float fval = *(double*)it.value.data();
|
|
BLEresult["read"] = fval;
|
|
break;
|
|
}
|
|
default:
|
|
BLEresult["read"] = it.value.c_str();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
it.complete = result;
|
|
BLEresult["success"] = result;
|
|
if (result || it.ttl <= 1) {
|
|
pubBT(BLEresult);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
void LYWSD03MMC_connect::notifyCB(NimBLERemoteCharacteristic* pChar, uint8_t* pData, size_t length, bool isNotify) {
|
|
if (m_taskHandle == nullptr) {
|
|
return;
|
|
}
|
|
if (!ProcessLock) {
|
|
Log.trace(F("Callback from %s characteristic" CR), pChar->getUUID().toString().c_str());
|
|
|
|
if (length == 5) {
|
|
Log.trace(F("Device identified creating BLE buffer" CR));
|
|
JsonObject BLEdata = getBTJsonObject();
|
|
String mac_address = m_pClient->getPeerAddress().toString().c_str();
|
|
mac_address.toUpperCase();
|
|
for (std::vector<BLEdevice*>::iterator it = devices.begin(); it != devices.end(); ++it) {
|
|
BLEdevice* p = *it;
|
|
if ((strcmp(p->macAdr, (char*)mac_address.c_str()) == 0)) {
|
|
if (p->sensorModel_id == BLEconectable::id::LYWSD03MMC)
|
|
BLEdata["model"] = "LYWSD03MMC";
|
|
else if (p->sensorModel_id == BLEconectable::id::MHO_C401)
|
|
BLEdata["model"] = "MHO-C401";
|
|
}
|
|
}
|
|
BLEdata["id"] = (char*)mac_address.c_str();
|
|
Log.trace(F("Device identified in CB: %s" CR), (char*)mac_address.c_str());
|
|
BLEdata["tempc"] = (float)((pData[0] | (pData[1] << 8)) * 0.01);
|
|
BLEdata["tempf"] = (float)(convertTemp_CtoF((pData[0] | (pData[1] << 8)) * 0.01));
|
|
BLEdata["hum"] = (float)(pData[2]);
|
|
BLEdata["volt"] = (float)(((pData[4] * 256) + pData[3]) / 1000.0);
|
|
BLEdata["batt"] = (float)(((((pData[4] * 256) + pData[3]) / 1000.0) - 2.1) * 100);
|
|
|
|
pubBT(BLEdata);
|
|
} else {
|
|
Log.notice(F("Invalid notification data" CR));
|
|
return;
|
|
}
|
|
} else {
|
|
Log.trace(F("Callback process canceled by processLock" CR));
|
|
}
|
|
|
|
xTaskNotifyGive(m_taskHandle);
|
|
}
|
|
|
|
void LYWSD03MMC_connect::publishData() {
|
|
NimBLEUUID serviceUUID("ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6");
|
|
NimBLEUUID charUUID("ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6");
|
|
NimBLERemoteCharacteristic* pChar = getCharacteristic(serviceUUID, charUUID);
|
|
|
|
if (pChar && pChar->canNotify()) {
|
|
Log.trace(F("Registering notification" CR));
|
|
if (pChar->subscribe(true, std::bind(&LYWSD03MMC_connect::notifyCB, this,
|
|
std::placeholders::_1, std::placeholders::_2,
|
|
std::placeholders::_3, std::placeholders::_4))) {
|
|
m_taskHandle = xTaskGetCurrentTaskHandle();
|
|
if (ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(BLE_CNCT_TIMEOUT)) == pdFALSE) {
|
|
m_taskHandle = nullptr;
|
|
}
|
|
} else {
|
|
Log.notice(F("Failed registering notification" CR));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void DT24_connect::notifyCB(NimBLERemoteCharacteristic* pChar, uint8_t* pData, size_t length, bool isNotify) {
|
|
if (m_taskHandle == nullptr) {
|
|
return;
|
|
}
|
|
|
|
if (!ProcessLock) {
|
|
Log.trace(F("Callback from %s characteristic" CR), pChar->getUUID().toString().c_str());
|
|
if (length == 20) {
|
|
m_data.assign(pData, pData + length);
|
|
return;
|
|
} else if (m_data.size() == 20 && length == 16) {
|
|
m_data.insert(m_data.end(), pData, pData + length);
|
|
|
|
|
|
|
|
|
|
Log.trace(F("Device identified creating BLE buffer" CR));
|
|
JsonObject& BLEdata = getBTJsonObject();
|
|
String mac_address = m_pClient->getPeerAddress().toString().c_str();
|
|
mac_address.toUpperCase();
|
|
BLEdata["model"] = "DT24";
|
|
BLEdata["id"] = (char*)mac_address.c_str();
|
|
Log.trace(F("Device identified in CB: %s" CR), (char*)mac_address.c_str());
|
|
BLEdata["volt"] = (float)(((m_data[4] * 256 * 256) + (m_data[5] * 256) + m_data[6]) / 10.0);
|
|
BLEdata["current"] = (float)(((m_data[7] * 256 * 256) + (m_data[8] * 256) + m_data[9]) / 1000.0);
|
|
BLEdata["power"] = (float)(((m_data[10] * 256 * 256) + (m_data[11] * 256) + m_data[12]) / 10.0);
|
|
BLEdata["energy"] = (float)(((m_data[13] * 256 * 256 * 256) + (m_data[14] * 256 * 256) + (m_data[15] * 256) + m_data[16]) / 100.0);
|
|
BLEdata["price"] = (float)(((m_data[17] * 256 * 256) + (m_data[18] * 256) + m_data[19]) / 100.0);
|
|
BLEdata["tempc"] = (float)(m_data[24] * 256) + m_data[25];
|
|
BLEdata["tempf"] = (float)(convertTemp_CtoF((m_data[24] * 256) + m_data[25]));
|
|
|
|
pubBT(BLEdata);
|
|
} else {
|
|
Log.notice(F("Invalid notification data" CR));
|
|
return;
|
|
}
|
|
} else {
|
|
Log.trace(F("Callback process canceled by processLock" CR));
|
|
}
|
|
|
|
xTaskNotifyGive(m_taskHandle);
|
|
}
|
|
|
|
void DT24_connect::publishData() {
|
|
NimBLEUUID serviceUUID("ffe0");
|
|
NimBLEUUID charUUID("ffe1");
|
|
NimBLERemoteCharacteristic* pChar = getCharacteristic(serviceUUID, charUUID);
|
|
|
|
if (pChar && pChar->canNotify()) {
|
|
Log.trace(F("Registering notification" CR));
|
|
if (pChar->subscribe(true, std::bind(&DT24_connect::notifyCB, this,
|
|
std::placeholders::_1, std::placeholders::_2,
|
|
std::placeholders::_3, std::placeholders::_4))) {
|
|
m_taskHandle = xTaskGetCurrentTaskHandle();
|
|
if (ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(BLE_CNCT_TIMEOUT)) == pdFALSE) {
|
|
m_taskHandle = nullptr;
|
|
}
|
|
} else {
|
|
Log.notice(F("Failed registering notification" CR));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void HHCCJCY01HHCC_connect::publishData() {
|
|
NimBLEUUID serviceUUID("00001204-0000-1000-8000-00805f9b34fb");
|
|
NimBLEUUID charUUID("00001a00-0000-1000-8000-00805f9b34fb");
|
|
NimBLEUUID charUUID2("00001a02-0000-1000-8000-00805f9b34fb");
|
|
NimBLERemoteCharacteristic* pChar = getCharacteristic(serviceUUID, charUUID);
|
|
|
|
if (pChar) {
|
|
Log.trace(F("Read mode" CR));
|
|
uint8_t buf[2] = {0xA0, 0x1F};
|
|
pChar->writeValue(buf, 2, true);
|
|
int batteryValue = -1;
|
|
NimBLERemoteCharacteristic* pChar2 = getCharacteristic(serviceUUID, charUUID2);
|
|
if (pChar2) {
|
|
std::string value;
|
|
value = pChar2->readValue();
|
|
const char* val2 = value.c_str();
|
|
batteryValue = val2[0];
|
|
JsonObject& BLEdata = getBTJsonObject();
|
|
String mac_address = m_pClient->getPeerAddress().toString().c_str();
|
|
mac_address.toUpperCase();
|
|
BLEdata["model"] = "HHCCJCY01HHCC";
|
|
BLEdata["id"] = (char*)mac_address.c_str();
|
|
BLEdata["batt"] = (int)batteryValue;
|
|
pubBT(BLEdata);
|
|
} else {
|
|
Log.notice(F("Failed getting characteristic" CR));
|
|
}
|
|
} else {
|
|
Log.notice(F("Failed getting characteristic" CR));
|
|
}
|
|
}
|
|
|
|
|
|
void XMWSDJ04MMC_connect::notifyCB(NimBLERemoteCharacteristic* pChar, uint8_t* pData, size_t length, bool isNotify) {
|
|
if (m_taskHandle == nullptr) {
|
|
return;
|
|
}
|
|
if (!ProcessLock) {
|
|
Log.trace(F("Callback from %s characteristic" CR), pChar->getUUID().toString().c_str());
|
|
|
|
if (length == 6) {
|
|
Log.trace(F("Device identified creating BLE buffer" CR));
|
|
JsonObject BLEdata = getBTJsonObject();
|
|
String mac_address = m_pClient->getPeerAddress().toString().c_str();
|
|
mac_address.toUpperCase();
|
|
BLEdata["model"] = "XMWSDJ04MMC";
|
|
BLEdata["id"] = (char*)mac_address.c_str();
|
|
Log.trace(F("Device identified in CB: %s" CR), (char*)mac_address.c_str());
|
|
BLEdata["tempc"] = (float)((pData[0] | (pData[1] << 8)) * 0.1);
|
|
BLEdata["tempf"] = (float)(convertTemp_CtoF((pData[0] | (pData[1] << 8)) * 0.1));
|
|
BLEdata["hum"] = (float)((pData[2] | (pData[3] << 8)) * 0.1);
|
|
BLEdata["volt"] = (float)((pData[4] | (pData[5] << 8)) / 1000.0);
|
|
BLEdata["batt"] = (float)((((pData[4] | (pData[5] << 8)) / 1000.0) - 2.1) * 100);
|
|
|
|
pubBT(BLEdata);
|
|
} else {
|
|
Log.notice(F("Invalid notification data" CR));
|
|
return;
|
|
}
|
|
} else {
|
|
Log.trace(F("Callback process canceled by processLock" CR));
|
|
}
|
|
|
|
xTaskNotifyGive(m_taskHandle);
|
|
}
|
|
|
|
void XMWSDJ04MMC_connect::publishData() {
|
|
NimBLEUUID serviceUUID("ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6");
|
|
NimBLEUUID charUUID("ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6");
|
|
NimBLERemoteCharacteristic* pChar = getCharacteristic(serviceUUID, charUUID);
|
|
|
|
if (pChar && pChar->canNotify()) {
|
|
Log.trace(F("Registering notification" CR));
|
|
if (pChar->subscribe(true, std::bind(&XMWSDJ04MMC_connect::notifyCB, this,
|
|
std::placeholders::_1, std::placeholders::_2,
|
|
std::placeholders::_3, std::placeholders::_4))) {
|
|
m_taskHandle = xTaskGetCurrentTaskHandle();
|
|
if (ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(BLE_CNCT_TIMEOUT)) == pdFALSE) {
|
|
m_taskHandle = nullptr;
|
|
}
|
|
} else {
|
|
Log.notice(F("Failed registering notification" CR));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void SBS1_connect::notifyCB(NimBLERemoteCharacteristic* pChar, uint8_t* pData, size_t length, bool isNotify) {
|
|
if (m_taskHandle == nullptr) {
|
|
return;
|
|
}
|
|
if (!ProcessLock) {
|
|
Log.trace(F("Callback from %s characteristic" CR), pChar->getUUID().toString().c_str());
|
|
|
|
if (length) {
|
|
m_notifyVal = *pData;
|
|
} else {
|
|
Log.notice(F("Invalid notification data" CR));
|
|
return;
|
|
}
|
|
} else {
|
|
Log.trace(F("Callback process canceled by processLock" CR));
|
|
}
|
|
|
|
xTaskNotifyGive(m_taskHandle);
|
|
}
|
|
|
|
bool SBS1_connect::processActions(std::vector<BLEAction>& actions) {
|
|
NimBLEUUID serviceUUID("cba20d00-224d-11e6-9fb8-0002a5d5c51b");
|
|
NimBLEUUID charUUID("cba20002-224d-11e6-9fb8-0002a5d5c51b");
|
|
NimBLEUUID notifyCharUUID("cba20003-224d-11e6-9fb8-0002a5d5c51b");
|
|
static byte ON[] = {0x57, 0x01, 0x01};
|
|
static byte OFF[] = {0x57, 0x01, 0x02};
|
|
|
|
bool result = false;
|
|
if (actions.size() > 0) {
|
|
for (auto& it : actions) {
|
|
if (NimBLEAddress(it.addr) == m_pClient->getPeerAddress()) {
|
|
NimBLERemoteCharacteristic* pChar = getCharacteristic(serviceUUID, charUUID);
|
|
NimBLERemoteCharacteristic* pNotifyChar = getCharacteristic(serviceUUID, notifyCharUUID);
|
|
|
|
if (it.write && pChar && pNotifyChar) {
|
|
Log.trace(F("processing Switchbot %s" CR), it.value.c_str());
|
|
if (pNotifyChar->subscribe(true,
|
|
std::bind(&SBS1_connect::notifyCB,
|
|
this, std::placeholders::_1, std::placeholders::_2,
|
|
std::placeholders::_3, std::placeholders::_4),
|
|
true)) {
|
|
if (it.value == "on") {
|
|
result = pChar->writeValue(ON, 3, false);
|
|
} else {
|
|
result = pChar->writeValue(OFF, 3, false);
|
|
}
|
|
|
|
if (result) {
|
|
m_taskHandle = xTaskGetCurrentTaskHandle();
|
|
if (ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(BLE_CNCT_TIMEOUT)) == pdFALSE) {
|
|
m_taskHandle = nullptr;
|
|
}
|
|
result = m_notifyVal == 0x01;
|
|
}
|
|
}
|
|
}
|
|
|
|
it.complete = result;
|
|
if (result || it.ttl <= 1) {
|
|
JsonObject BLEresult = getBTJsonObject();
|
|
BLEresult["id"] = it.addr;
|
|
BLEresult["state"] = result ? it.value : it.value == "on" ? "off" : "on";
|
|
pubBT(BLEresult);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
# endif
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayBT.ino"
|
|
# 31 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayBT.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZgatewayBT
|
|
|
|
# include "FreeRTOS.h"
|
|
SemaphoreHandle_t semaphoreCreateOrUpdateDevice;
|
|
SemaphoreHandle_t semaphoreBLEOperation;
|
|
QueueHandle_t BLEQueue;
|
|
|
|
# include <NimBLEAdvertisedDevice.h>
|
|
# include <NimBLEDevice.h>
|
|
# include <NimBLEScan.h>
|
|
# include <NimBLEUtils.h>
|
|
# include <decoder.h>
|
|
# include <driver/adc.h>
|
|
# include <esp_bt.h>
|
|
# include <esp_bt_main.h>
|
|
# include <esp_wifi.h>
|
|
# include <stdatomic.h>
|
|
|
|
# include <vector>
|
|
|
|
# include "ZgatewayBLEConnect.h"
|
|
# include "soc/timer_group_reg.h"
|
|
# include "soc/timer_group_struct.h"
|
|
|
|
using namespace std;
|
|
|
|
|
|
BTConfig_s BTConfig;
|
|
|
|
#define device_flags_init 0 << 0
|
|
#define device_flags_isDisc 1 << 0
|
|
#define device_flags_isWhiteL 1 << 1
|
|
#define device_flags_isBlackL 1 << 2
|
|
#define device_flags_connect 1 << 3
|
|
|
|
TheengsDecoder decoder;
|
|
|
|
struct decompose {
|
|
int start;
|
|
int len;
|
|
bool reverse;
|
|
};
|
|
|
|
vector<BLEAction> BLEactions;
|
|
|
|
vector<BLEdevice*> devices;
|
|
int newDevices = 0;
|
|
|
|
static BLEdevice NO_DEVICE_FOUND = {{0},
|
|
0,
|
|
false,
|
|
false,
|
|
false,
|
|
false,
|
|
TheengsDecoder::BLE_ID_NUM::UNKNOWN_MODEL};
|
|
static bool oneWhite = false;
|
|
|
|
void BTConfig_init() {
|
|
BTConfig.bleConnect = AttemptBLEConnect;
|
|
BTConfig.BLEinterval = TimeBtwRead;
|
|
BTConfig.BLEscanBeforeConnect = ScanBeforeConnect;
|
|
BTConfig.pubOnlySensors = PublishOnlySensors;
|
|
BTConfig.presenceEnable = HassPresence;
|
|
BTConfig.presenceTopic = subjectHomePresence;
|
|
BTConfig.presenceUseBeaconUuid = useBeaconUuidForPresence;
|
|
BTConfig.minRssi = MinimumRSSI;
|
|
BTConfig.extDecoderEnable = UseExtDecoder;
|
|
BTConfig.extDecoderTopic = MQTTDecodeTopic;
|
|
BTConfig.filterConnectable = BLE_FILTER_CONNECTABLE;
|
|
BTConfig.pubKnownServiceData = pubKnownBLEServiceData;
|
|
BTConfig.pubUnknownServiceData = pubUnknownBLEServiceData;
|
|
BTConfig.pubKnownManufData = pubBLEManufacturerData;
|
|
BTConfig.pubUnknownManufData = pubUnknownBLEManufacturerData;
|
|
BTConfig.pubServiceDataUUID = pubBLEServiceUUID;
|
|
BTConfig.pubBeaconUuidForTopic = useBeaconUuidForTopic;
|
|
BTConfig.ignoreWBlist = false;
|
|
}
|
|
|
|
template <typename T>
|
|
void BTConfig_update(JsonObject& data, const char* key, T& var);
|
|
template <typename T>
|
|
void BTConfig_update(JsonObject& data, const char* key, T& var) {
|
|
if (data.containsKey(key)) {
|
|
if (var != data[key].as<T>()) {
|
|
var = data[key].as<T>();
|
|
Log.notice(F("BT config %s changed: %s" CR), key, data[key].as<String>());
|
|
} else {
|
|
Log.notice(F("BT config %s unchanged: %s" CR), key, data[key].as<String>());
|
|
}
|
|
}
|
|
}
|
|
|
|
void BTConfig_fromJson(JsonObject& BTdata, bool startup = false) {
|
|
|
|
BTConfig_update(BTdata, "bleconnect", BTConfig.bleConnect);
|
|
|
|
if (BTdata.containsKey("interval") && BTdata["interval"] != 0)
|
|
BTConfig_update(BTdata, "interval", BTConfig.BLEinterval);
|
|
|
|
BTConfig_update(BTdata, "scanbcnct", BTConfig.BLEscanBeforeConnect);
|
|
|
|
BTConfig_update(BTdata, "onlysensors", BTConfig.pubOnlySensors);
|
|
|
|
BTConfig_update(BTdata, "hasspresence", BTConfig.presenceEnable);
|
|
|
|
BTConfig_update(BTdata, "presenceTopic", BTConfig.presenceTopic);
|
|
|
|
BTConfig_update(BTdata, "presenceUseBeaconUuid", BTConfig.presenceUseBeaconUuid);
|
|
|
|
BTConfig_update(BTdata, "minrssi", BTConfig.minRssi);
|
|
|
|
BTConfig_update(BTdata, "extDecoderEnable", BTConfig.extDecoderEnable);
|
|
|
|
BTConfig_update(BTdata, "extDecoderTopic", BTConfig.extDecoderTopic);
|
|
|
|
BTConfig_update(BTdata, "filterConnectable", BTConfig.filterConnectable);
|
|
|
|
BTConfig_update(BTdata, "pubKnownServiceData", BTConfig.pubKnownServiceData);
|
|
|
|
BTConfig_update(BTdata, "pubUnknownServiceData", BTConfig.pubUnknownServiceData);
|
|
|
|
BTConfig_update(BTdata, "pubKnownManufData", BTConfig.pubKnownManufData);
|
|
|
|
BTConfig_update(BTdata, "pubUnknownManufData", BTConfig.pubUnknownManufData);
|
|
|
|
BTConfig_update(BTdata, "pubServiceDataUUID", BTConfig.pubServiceDataUUID);
|
|
|
|
BTConfig_update(BTdata, "pubBeaconUuidForTopic", BTConfig.pubBeaconUuidForTopic);
|
|
|
|
BTConfig_update(BTdata, "ignoreWBlist", (BTConfig.ignoreWBlist));
|
|
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject jo = jsonBuffer.to<JsonObject>();
|
|
jo["bleconnect"] = BTConfig.bleConnect;
|
|
jo["interval"] = BTConfig.BLEinterval;
|
|
jo["scanbcnct"] = BTConfig.BLEscanBeforeConnect;
|
|
jo["onlysensors"] = BTConfig.pubOnlySensors;
|
|
jo["hasspresence"] = BTConfig.presenceEnable;
|
|
jo["presenceTopic"] = BTConfig.presenceTopic;
|
|
jo["presenceUseBeaconUuid"] = BTConfig.presenceUseBeaconUuid;
|
|
jo["minrssi"] = -abs(BTConfig.minRssi);
|
|
jo["extDecoderEnable"] = BTConfig.extDecoderEnable;
|
|
jo["extDecoderTopic"] = BTConfig.extDecoderTopic;
|
|
jo["filterConnectable"] = BTConfig.filterConnectable;
|
|
jo["pubKnownServiceData"] = BTConfig.pubKnownServiceData;
|
|
jo["pubUnknownServiceData"] = BTConfig.pubUnknownServiceData;
|
|
jo["pubKnownManufData"] = BTConfig.pubKnownManufData;
|
|
jo["pubUnknownManufData"] = BTConfig.pubUnknownManufData;
|
|
jo["pubServiceDataUUID"] = BTConfig.pubServiceDataUUID;
|
|
jo["pubBeaconUuidForTopic"] = BTConfig.pubBeaconUuidForTopic;
|
|
jo["ignoreWBlist"] = BTConfig.ignoreWBlist;
|
|
|
|
if (startup) {
|
|
Log.notice(F("BT config: "));
|
|
serializeJsonPretty(jsonBuffer, Serial);
|
|
Serial.println();
|
|
return;
|
|
}
|
|
pub("/commands/BTtoMQTT/config", jo);
|
|
|
|
if (BTdata.containsKey("erase") && BTdata["erase"].as<bool>()) {
|
|
|
|
preferences.begin(Gateway_Short_Name, false);
|
|
preferences.remove("BTConfig");
|
|
preferences.end();
|
|
Log.notice(F("BT config erased" CR));
|
|
return;
|
|
}
|
|
|
|
if (BTdata.containsKey("save") && BTdata["save"].as<bool>()) {
|
|
|
|
String conf = "";
|
|
serializeJson(jsonBuffer, conf);
|
|
preferences.begin(Gateway_Short_Name, false);
|
|
preferences.putString("BTConfig", conf);
|
|
preferences.end();
|
|
Log.notice(F("BT config saved" CR));
|
|
}
|
|
}
|
|
|
|
void BTConfig_load() {
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
preferences.begin(Gateway_Short_Name, true);
|
|
auto error = deserializeJson(jsonBuffer, preferences.getString("BTConfig", "{}"));
|
|
preferences.end();
|
|
Log.notice(F("BT config loaded" CR));
|
|
if (error) {
|
|
Log.error(F("BT config deserialization failed: %s, buffer capacity: %u" CR), error.c_str(), jsonBuffer.capacity());
|
|
return;
|
|
}
|
|
if (jsonBuffer.isNull()) {
|
|
Log.warning(F("BT config is null" CR));
|
|
return;
|
|
}
|
|
JsonObject jo = jsonBuffer.as<JsonObject>();
|
|
BTConfig_fromJson(jo, true);
|
|
Log.notice(F("BT config loaded" CR));
|
|
}
|
|
|
|
void pubBTMainCore(JsonObject& data, bool haPresenceEnabled = true) {
|
|
if (abs((int)data["rssi"] | 0) < abs(BTConfig.minRssi) && data.containsKey("id")) {
|
|
String topic = data["id"].as<const char*>();
|
|
topic.replace(":", "");
|
|
if (BTConfig.pubBeaconUuidForTopic && !BTConfig.extDecoderEnable && data.containsKey("model_id") && data["model_id"].as<String>() == "IBEACON")
|
|
topic = data["uuid"].as<const char*>();
|
|
if (BTConfig.extDecoderEnable && !data.containsKey("model"))
|
|
topic = BTConfig.extDecoderTopic;
|
|
topic = subjectBTtoMQTT + String("/") + topic;
|
|
pub((char*)topic.c_str(), data);
|
|
}
|
|
if (haPresenceEnabled && data.containsKey("distance")) {
|
|
if (data.containsKey("servicedatauuid"))
|
|
data.remove("servicedatauuid");
|
|
if (data.containsKey("servicedata"))
|
|
data.remove("servicedata");
|
|
if (BTConfig.presenceUseBeaconUuid && data.containsKey("model_id") && data["model_id"].as<String>() == "IBEACON") {
|
|
data["mac"] = data["id"];
|
|
data["id"] = data["uuid"];
|
|
}
|
|
String topic = String(mqtt_topic) + BTConfig.presenceTopic + String(gateway_name);
|
|
Log.trace(F("Pub HA Presence %s" CR), topic.c_str());
|
|
pub_custom_topic((char*)topic.c_str(), data, false);
|
|
}
|
|
}
|
|
|
|
class JsonBundle {
|
|
public:
|
|
StaticJsonDocument<JSON_MSG_BUFFER> buffer;
|
|
JsonObject object;
|
|
bool haPresence;
|
|
|
|
JsonObject& createObject(const char* json = NULL, bool haPresenceEnabled = true) {
|
|
buffer.clear();
|
|
haPresence = haPresenceEnabled;
|
|
object = buffer.to<JsonObject>();
|
|
|
|
if (json != nullptr) {
|
|
auto error = deserializeJson(buffer, json);
|
|
if (error) {
|
|
Log.error(F("deserialize object failed: %s" CR), error.c_str());
|
|
}
|
|
}
|
|
return object;
|
|
}
|
|
};
|
|
|
|
void PublishDeviceData(JsonObject& BLEdata, bool processBLEData = true);
|
|
|
|
static TaskHandle_t xCoreTaskHandle;
|
|
static TaskHandle_t xProcBLETaskHandle;
|
|
|
|
atomic_int forceBTScan;
|
|
|
|
JsonBundle jsonBTBufferQueue[BTQueueSize];
|
|
atomic_int jsonBTBufferQueueNext, jsonBTBufferQueueLast;
|
|
int btQueueBlocked = 0;
|
|
int btQueueLengthSum = 0;
|
|
int btQueueLengthCount = 0;
|
|
|
|
JsonObject& getBTJsonObject(const char* json, bool haPresenceEnabled) {
|
|
int next, last;
|
|
for (bool blocked = false;;) {
|
|
next = atomic_load_explicit(&jsonBTBufferQueueNext, ::memory_order_seq_cst);
|
|
last = atomic_load_explicit(&jsonBTBufferQueueLast, ::memory_order_seq_cst);
|
|
if ((2 * BTQueueSize + last - next) % (2 * BTQueueSize) != BTQueueSize) break;
|
|
if (!blocked) {
|
|
blocked = true;
|
|
btQueueBlocked++;
|
|
}
|
|
delay(1);
|
|
}
|
|
return jsonBTBufferQueue[last % BTQueueSize].createObject(json, haPresenceEnabled);
|
|
}
|
|
|
|
|
|
void pubBT(JsonObject& data) {
|
|
int last = atomic_load_explicit(&jsonBTBufferQueueLast, ::memory_order_seq_cst);
|
|
atomic_store_explicit(&jsonBTBufferQueueLast, (last + 1) % (2 * BTQueueSize), ::memory_order_seq_cst);
|
|
}
|
|
|
|
|
|
void emptyBTQueue() {
|
|
for (bool first = true;;) {
|
|
int next = atomic_load_explicit(&jsonBTBufferQueueNext, ::memory_order_seq_cst);
|
|
int last = atomic_load_explicit(&jsonBTBufferQueueLast, ::memory_order_seq_cst);
|
|
if (last == next) break;
|
|
if (first) {
|
|
int diff = (2 * BTQueueSize + last - next) % (2 * BTQueueSize);
|
|
btQueueLengthSum += diff;
|
|
btQueueLengthCount++;
|
|
first = false;
|
|
}
|
|
JsonBundle& bundle = jsonBTBufferQueue[next % BTQueueSize];
|
|
pubBTMainCore(bundle.object, bundle.haPresence);
|
|
atomic_store_explicit(&jsonBTBufferQueueNext, (next + 1) % (2 * BTQueueSize), ::memory_order_seq_cst);
|
|
vTaskDelay(1);
|
|
}
|
|
}
|
|
|
|
bool ProcessLock = false;
|
|
|
|
void createOrUpdateDevice(const char* mac, uint8_t flags, int model, int mac_type = 0);
|
|
|
|
BLEdevice* getDeviceByMac(const char* mac);
|
|
BLEdevice* getDeviceByMac(const char* mac) {
|
|
Log.trace(F("getDeviceByMac %s" CR), mac);
|
|
|
|
for (vector<BLEdevice*>::iterator it = devices.begin(); it != devices.end(); ++it) {
|
|
if ((strcmp((*it)->macAdr, mac) == 0)) {
|
|
return *it;
|
|
}
|
|
}
|
|
return &NO_DEVICE_FOUND;
|
|
}
|
|
|
|
bool updateWorB(JsonObject& BTdata, bool isWhite) {
|
|
Log.trace(F("update WorB" CR));
|
|
const char* jsonKey = isWhite ? "white-list" : "black-list";
|
|
|
|
int size = BTdata[jsonKey].size();
|
|
if (size == 0)
|
|
return false;
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
const char* mac = BTdata[jsonKey][i];
|
|
createOrUpdateDevice(mac, (isWhite ? device_flags_isWhiteL : device_flags_isBlackL),
|
|
TheengsDecoder::BLE_ID_NUM::UNKNOWN_MODEL);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void createOrUpdateDevice(const char* mac, uint8_t flags, int model, int mac_type) {
|
|
if (xSemaphoreTake(semaphoreCreateOrUpdateDevice, pdMS_TO_TICKS(30000)) == pdFALSE) {
|
|
Log.error(F("Semaphore NOT taken" CR));
|
|
return;
|
|
}
|
|
|
|
BLEdevice* device = getDeviceByMac(mac);
|
|
if (device == &NO_DEVICE_FOUND) {
|
|
Log.trace(F("add %s" CR), mac);
|
|
|
|
device = new BLEdevice();
|
|
strcpy(device->macAdr, mac);
|
|
device->isDisc = flags & device_flags_isDisc;
|
|
device->isWhtL = flags & device_flags_isWhiteL;
|
|
device->isBlkL = flags & device_flags_isBlackL;
|
|
device->connect = flags & device_flags_connect;
|
|
device->macType = mac_type;
|
|
device->sensorModel_id = model;
|
|
devices.push_back(device);
|
|
newDevices++;
|
|
} else {
|
|
Log.trace(F("update %s" CR), mac);
|
|
|
|
device->macType = mac_type;
|
|
|
|
if (flags & device_flags_isDisc) {
|
|
device->isDisc = true;
|
|
}
|
|
|
|
if (flags & device_flags_connect) {
|
|
device->connect = true;
|
|
}
|
|
|
|
if (model != TheengsDecoder::BLE_ID_NUM::UNKNOWN_MODEL) {
|
|
device->sensorModel_id = model;
|
|
}
|
|
|
|
if (flags & device_flags_isWhiteL || flags & device_flags_isBlackL) {
|
|
device->isWhtL = flags & device_flags_isWhiteL;
|
|
device->isBlkL = flags & device_flags_isBlackL;
|
|
}
|
|
}
|
|
|
|
|
|
oneWhite = oneWhite || device->isWhtL;
|
|
|
|
xSemaphoreGive(semaphoreCreateOrUpdateDevice);
|
|
}
|
|
|
|
#define isWhite(device) device->isWhtL
|
|
#define isBlack(device) device->isBlkL
|
|
#define isDiscovered(device) device->isDisc
|
|
|
|
void dumpDevices() {
|
|
for (vector<BLEdevice*>::iterator it = devices.begin(); it != devices.end(); ++it) {
|
|
BLEdevice* p = *it;
|
|
Log.trace(F("macAdr %s" CR), p->macAdr);
|
|
Log.trace(F("macType %d" CR), p->macType);
|
|
Log.trace(F("isDisc %d" CR), p->isDisc);
|
|
Log.trace(F("isWhtL %d" CR), p->isWhtL);
|
|
Log.trace(F("isBlkL %d" CR), p->isBlkL);
|
|
Log.trace(F("connect %d" CR), p->connect);
|
|
Log.trace(F("sensorModel_id %d" CR), p->sensorModel_id);
|
|
}
|
|
}
|
|
|
|
void strupp(char* beg) {
|
|
while ((*beg = toupper(*beg)))
|
|
++beg;
|
|
}
|
|
|
|
# ifdef ZmqttDiscovery
|
|
void DT24Discovery(const char* mac, const char* sensorModel_id) {
|
|
#define DT24parametersCount 6
|
|
Log.trace(F("DT24Discovery" CR));
|
|
const char* DT24sensor[DT24parametersCount][9] = {
|
|
{"sensor", "volt", mac, "power", jsonVolt, "", "", "V", stateClassMeasurement},
|
|
{"sensor", "amp", mac, "power", jsonCurrent, "", "", "A", stateClassMeasurement},
|
|
{"sensor", "watt", mac, "power", jsonPower, "", "", "W", stateClassMeasurement},
|
|
{"sensor", "watt-hour", mac, "power", jsonEnergy, "", "", "kWh", stateClassMeasurement},
|
|
{"sensor", "price", mac, "", jsonMsg, "", "", "", stateClassNone},
|
|
{"sensor", "temp", mac, "temperature", jsonTempc, "", "", "°C", stateClassMeasurement}
|
|
|
|
};
|
|
|
|
createDiscoveryFromList(mac, DT24sensor, DT24parametersCount, "DT24", "ATorch", sensorModel_id);
|
|
}
|
|
|
|
void LYWSD03MMCDiscovery(const char* mac, const char* sensorModel) {
|
|
#define LYWSD03MMCparametersCount 4
|
|
Log.trace(F("LYWSD03MMCDiscovery" CR));
|
|
const char* LYWSD03MMCsensor[LYWSD03MMCparametersCount][9] = {
|
|
{"sensor", "batt", mac, "battery", jsonBatt, "", "", "%", stateClassMeasurement},
|
|
{"sensor", "volt", mac, "", jsonVolt, "", "", "V", stateClassMeasurement},
|
|
{"sensor", "temp", mac, "temperature", jsonTempc, "", "", "°C", stateClassMeasurement},
|
|
{"sensor", "hum", mac, "humidity", jsonHum, "", "", "%", stateClassMeasurement}
|
|
|
|
};
|
|
|
|
createDiscoveryFromList(mac, LYWSD03MMCsensor, LYWSD03MMCparametersCount, "LYWSD03MMC", "Xiaomi", sensorModel);
|
|
}
|
|
|
|
void MHO_C401Discovery(const char* mac, const char* sensorModel) {
|
|
#define MHO_C401parametersCount 4
|
|
Log.trace(F("MHO_C401Discovery" CR));
|
|
const char* MHO_C401sensor[MHO_C401parametersCount][9] = {
|
|
{"sensor", "batt", mac, "battery", jsonBatt, "", "", "%", stateClassMeasurement},
|
|
{"sensor", "volt", mac, "", jsonVolt, "", "", "V", stateClassMeasurement},
|
|
{"sensor", "temp", mac, "temperature", jsonTempc, "", "", "°C", stateClassMeasurement},
|
|
{"sensor", "hum", mac, "humidity", jsonHum, "", "", "%", stateClassMeasurement}
|
|
|
|
};
|
|
|
|
createDiscoveryFromList(mac, MHO_C401sensor, MHO_C401parametersCount, "MHO_C401", "Xiaomi", sensorModel);
|
|
}
|
|
|
|
void HHCCJCY01HHCCDiscovery(const char* mac, const char* sensorModel) {
|
|
#define HHCCJCY01HHCCparametersCount 5
|
|
Log.trace(F("HHCCJCY01HHCCDiscovery" CR));
|
|
const char* HHCCJCY01HHCCsensor[HHCCJCY01HHCCparametersCount][9] = {
|
|
{"sensor", "batt", mac, "battery", jsonBatt, "", "", "%", stateClassMeasurement},
|
|
{"sensor", "temp", mac, "temperature", jsonTempc, "", "", "°C", stateClassMeasurement},
|
|
{"sensor", "lux", mac, "illuminance", jsonLux, "", "", "lx", stateClassMeasurement},
|
|
{"sensor", "fer", mac, "", jsonFer, "", "", "µS/cm", stateClassMeasurement},
|
|
{"sensor", "moi", mac, "", jsonMoi, "", "", "%", stateClassMeasurement}
|
|
|
|
};
|
|
|
|
createDiscoveryFromList(mac, HHCCJCY01HHCCsensor, HHCCJCY01HHCCparametersCount, "HHCCJCY01HHCC", "Xiaomi", sensorModel);
|
|
}
|
|
|
|
void XMWSDJ04MMCDiscovery(const char* mac, const char* sensorModel) {
|
|
#define XMWSDJ04MMCparametersCount 4
|
|
Log.trace(F("XMWSDJ04MMCDiscovery" CR));
|
|
const char* XMWSDJ04MMCsensor[XMWSDJ04MMCparametersCount][9] = {
|
|
{"sensor", "batt", mac, "battery", jsonBatt, "", "", "%", stateClassMeasurement},
|
|
{"sensor", "volt", mac, "", jsonVolt, "", "", "V", stateClassMeasurement},
|
|
{"sensor", "temp", mac, "temperature", jsonTempc, "", "", "°C", stateClassMeasurement},
|
|
{"sensor", "hum", mac, "humidity", jsonHum, "", "", "%", stateClassMeasurement}
|
|
|
|
};
|
|
|
|
createDiscoveryFromList(mac, XMWSDJ04MMCsensor, XMWSDJ04MMCparametersCount, "XMWSDJ04MMC", "Xiaomi", sensorModel);
|
|
}
|
|
|
|
# else
|
|
void LYWSD03MMCDiscovery(const char* mac, const char* sensorModel) {}
|
|
void MHO_C401Discovery(const char* mac, const char* sensorModel) {}
|
|
void HHCCJCY01HHCCDiscovery(const char* mac, const char* sensorModel) {}
|
|
void DT24Discovery(const char* mac, const char* sensorModel_id) {}
|
|
void XMWSDJ04MMCDiscovery(const char* mac, const char* sensorModel_id) {}
|
|
# endif
|
|
# 525 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayBT.ino"
|
|
static int taskCore = 0;
|
|
|
|
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
|
|
void onResult(BLEAdvertisedDevice* advertisedDevice) {
|
|
if (xQueueSend(BLEQueue, &advertisedDevice, 0) != pdTRUE) {
|
|
Log.error(F("BLEQueue full" CR));
|
|
}
|
|
}
|
|
};
|
|
|
|
std::string convertServiceData(std::string deviceServiceData) {
|
|
int serviceDataLength = (int)deviceServiceData.length();
|
|
char spr[2 * serviceDataLength + 1];
|
|
for (int i = 0; i < serviceDataLength; i++) sprintf(spr + 2 * i, "%.2x", (unsigned char)deviceServiceData[i]);
|
|
spr[2 * serviceDataLength] = 0;
|
|
Log.trace("Converted service data (%d) to %s" CR, serviceDataLength, spr);
|
|
return spr;
|
|
}
|
|
|
|
void procBLETask(void* pvParameters) {
|
|
BLEAdvertisedDevice* advertisedDevice = nullptr;
|
|
|
|
for (;;) {
|
|
xQueueReceive(BLEQueue, &advertisedDevice, portMAX_DELAY);
|
|
|
|
if (!ProcessLock) {
|
|
Log.trace(F("Creating BLE buffer" CR));
|
|
JsonObject& BLEdata = getBTJsonObject();
|
|
String mac_adress = advertisedDevice->getAddress().toString().c_str();
|
|
mac_adress.toUpperCase();
|
|
BLEdata["id"] = (char*)mac_adress.c_str();
|
|
BLEdata["mac_type"] = advertisedDevice->getAddress().getType();
|
|
Log.notice(F("Device detected: %s" CR), (char*)mac_adress.c_str());
|
|
BLEdevice* device = getDeviceByMac(BLEdata["id"].as<const char*>());
|
|
|
|
if (BTConfig.filterConnectable && device->connect) {
|
|
Log.notice(F("Filtered connectable device" CR));
|
|
continue;
|
|
}
|
|
|
|
if (BTConfig.ignoreWBlist || ((!oneWhite || isWhite(device)) && !isBlack(device))) {
|
|
if (advertisedDevice->haveName())
|
|
BLEdata["name"] = (char*)advertisedDevice->getName().c_str();
|
|
if (advertisedDevice->haveManufacturerData()) {
|
|
char* manufacturerdata = BLEUtils::buildHexData(NULL, (uint8_t*)advertisedDevice->getManufacturerData().data(), advertisedDevice->getManufacturerData().length());
|
|
BLEdata["manufacturerdata"] = manufacturerdata;
|
|
free(manufacturerdata);
|
|
}
|
|
if (advertisedDevice->haveRSSI())
|
|
BLEdata["rssi"] = (int)advertisedDevice->getRSSI();
|
|
if (advertisedDevice->haveTXPower())
|
|
BLEdata["txpower"] = (int8_t)advertisedDevice->getTXPower();
|
|
if (advertisedDevice->haveRSSI() && !BTConfig.pubOnlySensors && BTConfig.presenceEnable) {
|
|
hass_presence(BLEdata);
|
|
}
|
|
if (advertisedDevice->haveServiceData()) {
|
|
int serviceDataCount = advertisedDevice->getServiceDataCount();
|
|
Log.trace(F("Get services data number: %d" CR), serviceDataCount);
|
|
for (int j = 0; j < serviceDataCount; j++) {
|
|
std::string service_data = convertServiceData(advertisedDevice->getServiceData(j));
|
|
Log.trace(F("Service data: %s" CR), service_data.c_str());
|
|
BLEdata["servicedata"] = (char*)service_data.c_str();
|
|
std::string serviceDatauuid = advertisedDevice->getServiceDataUUID(j).toString();
|
|
Log.trace(F("Service data UUID: %s" CR), (char*)serviceDatauuid.c_str());
|
|
BLEdata["servicedatauuid"] = (char*)serviceDatauuid.c_str();
|
|
process_bledata(BLEdata);
|
|
}
|
|
|
|
PublishDeviceData(BLEdata, false);
|
|
} else {
|
|
PublishDeviceData(BLEdata);
|
|
}
|
|
} else {
|
|
Log.trace(F("Filtered MAC device" CR));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void BLEscan() {
|
|
|
|
while (uxQueueMessagesWaiting(BLEQueue)) {
|
|
yield();
|
|
}
|
|
disableCore0WDT();
|
|
Log.notice(F("Scan begin" CR));
|
|
BLEScan* pBLEScan = BLEDevice::getScan();
|
|
MyAdvertisedDeviceCallbacks myCallbacks;
|
|
pBLEScan->setAdvertisedDeviceCallbacks(&myCallbacks);
|
|
pBLEScan->setActiveScan(ActiveBLEScan);
|
|
pBLEScan->setInterval(BLEScanInterval);
|
|
pBLEScan->setWindow(BLEScanWindow);
|
|
BLEScanResults foundDevices = pBLEScan->start(Scan_duration / 1000, false);
|
|
scanCount++;
|
|
Log.notice(F("Found %d devices, scan number %d end" CR), foundDevices.getCount(), scanCount);
|
|
enableCore0WDT();
|
|
Log.trace(F("Process BLE stack free: %u" CR), uxTaskGetStackHighWaterMark(xProcBLETaskHandle));
|
|
}
|
|
|
|
|
|
|
|
|
|
void BLEconnect() {
|
|
if (!ProcessLock) {
|
|
Log.notice(F("BLE Connect begin" CR));
|
|
do {
|
|
for (vector<BLEdevice*>::iterator it = devices.begin(); it != devices.end(); ++it) {
|
|
BLEdevice* p = *it;
|
|
if (p->connect) {
|
|
Log.trace(F("Model to connect found: %s" CR), p->macAdr);
|
|
NimBLEAddress addr((const char*)p->macAdr, p->macType);
|
|
if (p->sensorModel_id == BLEconectable::id::LYWSD03MMC ||
|
|
p->sensorModel_id == BLEconectable::id::MHO_C401) {
|
|
LYWSD03MMC_connect BLEclient(addr);
|
|
BLEclient.processActions(BLEactions);
|
|
BLEclient.publishData();
|
|
} else if (p->sensorModel_id == BLEconectable::id::DT24_BLE) {
|
|
DT24_connect BLEclient(addr);
|
|
BLEclient.processActions(BLEactions);
|
|
BLEclient.publishData();
|
|
} else if (p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::HHCCJCY01HHCC) {
|
|
HHCCJCY01HHCC_connect BLEclient(addr);
|
|
BLEclient.processActions(BLEactions);
|
|
BLEclient.publishData();
|
|
} else if (p->sensorModel_id == BLEconectable::id::XMWSDJ04MMC) {
|
|
XMWSDJ04MMC_connect BLEclient(addr);
|
|
BLEclient.processActions(BLEactions);
|
|
BLEclient.publishData();
|
|
} else if (p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::SBS1) {
|
|
SBS1_connect BLEclient(addr);
|
|
BLEclient.processActions(BLEactions);
|
|
} else {
|
|
GENERIC_connect BLEclient(addr);
|
|
if (BLEclient.processActions(BLEactions)) {
|
|
|
|
|
|
p->connect = false;
|
|
}
|
|
}
|
|
if (BLEactions.size() > 0) {
|
|
std::vector<BLEAction> swap;
|
|
for (auto& it : BLEactions) {
|
|
if (!it.complete && --it.ttl) {
|
|
swap.push_back(it);
|
|
} else if (memcmp(it.addr, p->macAdr, sizeof(it.addr)) == 0) {
|
|
if (p->sensorModel_id != BLEconectable::id::DT24_BLE &&
|
|
p->sensorModel_id != TheengsDecoder::BLE_ID_NUM::HHCCJCY01HHCC &&
|
|
p->sensorModel_id != BLEconectable::id::LYWSD03MMC &&
|
|
p->sensorModel_id != BLEconectable::id::MHO_C401 &&
|
|
p->sensorModel_id != BLEconectable::id::XMWSDJ04MMC) {
|
|
|
|
p->connect = false;
|
|
}
|
|
}
|
|
}
|
|
std::swap(BLEactions, swap);
|
|
}
|
|
}
|
|
}
|
|
} while (BLEactions.size() > 0);
|
|
Log.notice(F("BLE Connect end" CR));
|
|
}
|
|
}
|
|
|
|
void stopProcessing() {
|
|
Log.notice(F("Stop BLE processing" CR));
|
|
ProcessLock = true;
|
|
delay(Scan_duration < 2000 ? Scan_duration : 2000);
|
|
}
|
|
|
|
void startProcessing() {
|
|
Log.notice(F("Start BLE processing" CR));
|
|
ProcessLock = false;
|
|
vTaskResume(xCoreTaskHandle);
|
|
}
|
|
|
|
void coreTask(void* pvParameters) {
|
|
while (true) {
|
|
if (!ProcessLock) {
|
|
int n = 0;
|
|
while (client.state() != 0 && n <= InitialMQTTConnectionTimeout && !ProcessLock) {
|
|
n++;
|
|
delay(1000);
|
|
}
|
|
if (client.state() != 0) {
|
|
Log.warning(F("MQTT client disconnected no BLE scan" CR));
|
|
} else if (!ProcessLock) {
|
|
if (xSemaphoreTake(semaphoreBLEOperation, pdMS_TO_TICKS(30000)) == pdTRUE) {
|
|
BLEscan();
|
|
|
|
if ((!(scanCount % BTConfig.BLEscanBeforeConnect) || scanCount == 1) && BTConfig.bleConnect)
|
|
BLEconnect();
|
|
dumpDevices();
|
|
xSemaphoreGive(semaphoreBLEOperation);
|
|
} else {
|
|
Log.error(F("Failed to start scan - BLE busy" CR));
|
|
}
|
|
}
|
|
if (lowpowermode) {
|
|
lowPowerESP32();
|
|
int scan = atomic_exchange_explicit(&forceBTScan, 0, ::memory_order_seq_cst);
|
|
if (scan == 1) BTforceScan();
|
|
} else {
|
|
for (int interval = BTConfig.BLEinterval, waitms; interval > 0; interval -= waitms) {
|
|
int scan = atomic_exchange_explicit(&forceBTScan, 0, ::memory_order_seq_cst);
|
|
if (scan == 1) BTforceScan();
|
|
delay(waitms = interval > 100 ? 100 : interval);
|
|
}
|
|
}
|
|
} else {
|
|
Log.trace(F("BLE core task canceled by processLock" CR));
|
|
vTaskSuspend(xCoreTaskHandle);
|
|
}
|
|
}
|
|
}
|
|
|
|
void lowPowerESP32() {
|
|
Log.trace(F("Going to deep sleep for: %l s" CR), (BTConfig.BLEinterval / 1000));
|
|
deepSleep(BTConfig.BLEinterval * 1000);
|
|
}
|
|
|
|
void deepSleep(uint64_t time_in_us) {
|
|
# if defined(ZboardM5STACK) || defined(ZboardM5STICKC) || defined(ZboardM5STICKCP) || defined(ZboardM5TOUGH)
|
|
sleepScreen();
|
|
esp_sleep_enable_ext0_wakeup((gpio_num_t)SLEEP_BUTTON, LOW);
|
|
# endif
|
|
|
|
Log.trace(F("Deactivating ESP32 components" CR));
|
|
BLEDevice::deinit(true);
|
|
esp_bt_mem_release(ESP_BT_MODE_BTDM);
|
|
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
adc_power_off();
|
|
#pragma GCC diagnostic pop
|
|
esp_wifi_stop();
|
|
esp_deep_sleep(time_in_us);
|
|
}
|
|
|
|
void changelowpowermode(int newLowPowerMode) {
|
|
Log.notice(F("Changing LOW POWER mode to: %d" CR), newLowPowerMode);
|
|
# if defined(ZboardM5STACK) || defined(ZboardM5STICKC) || defined(ZboardM5STICKCP) || defined(ZboardM5TOUGH)
|
|
if (lowpowermode == 2) {
|
|
# ifdef ZboardM5STACK
|
|
M5.Lcd.wakeup();
|
|
# endif
|
|
# if defined(ZboardM5STICKC) || defined(ZboardM5STICKCP) || defined(ZboardM5TOUGH)
|
|
M5.Axp.SetLDO2(true);
|
|
M5.Lcd.begin();
|
|
# endif
|
|
}
|
|
char lpm[2];
|
|
sprintf(lpm, "%d", newLowPowerMode);
|
|
M5Print("Changing LOW POWER mode to:", lpm, "");
|
|
# endif
|
|
lowpowermode = newLowPowerMode;
|
|
preferences.begin(Gateway_Short_Name, false);
|
|
preferences.putUInt("lowpowermode", lowpowermode);
|
|
preferences.end();
|
|
}
|
|
|
|
void setupBT() {
|
|
BTConfig_init();
|
|
BTConfig_load();
|
|
Log.notice(F("BLE scans interval: %d" CR), BTConfig.BLEinterval);
|
|
Log.notice(F("BLE scans number before connect: %d" CR), BTConfig.BLEscanBeforeConnect);
|
|
Log.notice(F("Publishing only BLE sensors: %T" CR), BTConfig.pubOnlySensors);
|
|
Log.notice(F("minrssi: %d" CR), -abs(BTConfig.minRssi));
|
|
Log.notice(F("Low Power Mode: %d" CR), lowpowermode);
|
|
|
|
atomic_init(&forceBTScan, 0);
|
|
atomic_init(&jsonBTBufferQueueNext, 0);
|
|
atomic_init(&jsonBTBufferQueueLast, 0);
|
|
|
|
semaphoreCreateOrUpdateDevice = xSemaphoreCreateBinary();
|
|
xSemaphoreGive(semaphoreCreateOrUpdateDevice);
|
|
|
|
semaphoreBLEOperation = xSemaphoreCreateBinary();
|
|
xSemaphoreGive(semaphoreBLEOperation);
|
|
|
|
BLEQueue = xQueueCreate(32, sizeof(NimBLEAdvertisedDevice*));
|
|
|
|
BLEDevice::setScanDuplicateCacheSize(BLEScanDuplicateCacheSize);
|
|
BLEDevice::init("");
|
|
|
|
xTaskCreatePinnedToCore(
|
|
procBLETask,
|
|
"procBLETask",
|
|
5120,
|
|
NULL,
|
|
2,
|
|
&xProcBLETaskHandle,
|
|
1);
|
|
|
|
|
|
xTaskCreatePinnedToCore(
|
|
coreTask,
|
|
"coreTask",
|
|
10000,
|
|
NULL,
|
|
1,
|
|
&xCoreTaskHandle,
|
|
taskCore);
|
|
Log.trace(F("ZgatewayBT multicore ESP32 setup done " CR));
|
|
}
|
|
|
|
bool BTtoMQTT() {
|
|
BLEscan();
|
|
return true;
|
|
}
|
|
|
|
void RemoveJsonPropertyIf(JsonObject& obj, const char* key, bool condition) {
|
|
if (condition) {
|
|
Log.trace(F("Removing %s" CR), key);
|
|
obj.remove(key);
|
|
}
|
|
}
|
|
|
|
boolean valid_service_data(const char* data, int size) {
|
|
for (int i = 0; i < size; ++i) {
|
|
if (data[i] != 48)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
# ifdef ZmqttDiscovery
|
|
|
|
void launchBTDiscovery() {
|
|
if (newDevices == 0)
|
|
return;
|
|
if (xSemaphoreTake(semaphoreCreateOrUpdateDevice, pdMS_TO_TICKS(1000)) == pdFALSE) {
|
|
Log.error(F("Semaphore NOT taken" CR));
|
|
return;
|
|
}
|
|
newDevices = 0;
|
|
vector<BLEdevice*> localDevices = devices;
|
|
xSemaphoreGive(semaphoreCreateOrUpdateDevice);
|
|
for (vector<BLEdevice*>::iterator it = localDevices.begin(); it != localDevices.end(); ++it) {
|
|
BLEdevice* p = *it;
|
|
Log.trace(F("Device mac %s" CR), p->macAdr);
|
|
|
|
if (!isDiscovered(p) &&
|
|
p->sensorModel_id != TheengsDecoder::BLE_ID_NUM::IBEACON &&
|
|
p->sensorModel_id != TheengsDecoder::BLE_ID_NUM::MS_CDP &&
|
|
p->sensorModel_id != TheengsDecoder::BLE_ID_NUM::GAEN) {
|
|
String macWOdots = String(p->macAdr);
|
|
macWOdots.replace(":", "");
|
|
if (!BTConfig.extDecoderEnable &&
|
|
p->sensorModel_id > TheengsDecoder::BLE_ID_NUM::UNKNOWN_MODEL &&
|
|
p->sensorModel_id < TheengsDecoder::BLE_ID_NUM::BLE_ID_MAX &&
|
|
p->sensorModel_id != TheengsDecoder::BLE_ID_NUM::HHCCJCY01HHCC) {
|
|
Log.trace(F("Looking for Model_id: %d" CR), p->sensorModel_id);
|
|
std::string properties = decoder.getTheengProperties(p->sensorModel_id);
|
|
Log.trace(F("properties: %s" CR), properties.c_str());
|
|
std::string brand = decoder.getTheengAttribute(p->sensorModel_id, "brand");
|
|
std::string model = decoder.getTheengAttribute(p->sensorModel_id, "model");
|
|
std::string model_id = decoder.getTheengAttribute(p->sensorModel_id, "model_id");
|
|
if (!properties.empty()) {
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
deserializeJson(jsonBuffer, properties);
|
|
for (JsonPair prop : jsonBuffer["properties"].as<JsonObject>()) {
|
|
Log.trace("Key: %s", prop.key().c_str());
|
|
Log.trace("Unit: %s", prop.value()["unit"].as<const char*>());
|
|
Log.trace("Name: %s", prop.value()["name"].as<const char*>());
|
|
String discovery_topic = String(subjectBTtoMQTT) + "/" + macWOdots;
|
|
String entity_name = String(model_id.c_str()) + "-" + String(prop.key().c_str());
|
|
String unique_id = macWOdots + "-" + String(prop.key().c_str());
|
|
# if OpenHABDiscovery
|
|
String value_template = "{{ value_json." + String(prop.key().c_str()) + "}}";
|
|
# else
|
|
String value_template = "{{ value_json." + String(prop.key().c_str()) + " | is_defined }}";
|
|
# endif
|
|
if (p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::SBS1 && !strcmp(prop.key().c_str(), "state")) {
|
|
String payload_on = "{\"SBS1\":\"on\",\"mac\":\"" + String(p->macAdr) + "\"}";
|
|
String payload_off = "{\"SBS1\":\"off\",\"mac\":\"" + String(p->macAdr) + "\"}";
|
|
createDiscovery("switch",
|
|
discovery_topic.c_str(), entity_name.c_str(), unique_id.c_str(),
|
|
will_Topic, "switch", value_template.c_str(),
|
|
payload_on.c_str(), payload_off.c_str(), "", 0,
|
|
Gateway_AnnouncementMsg, will_Message, false, subjectMQTTtoBTset,
|
|
model.c_str(), brand.c_str(), model_id.c_str(), macWOdots.c_str(), false,
|
|
stateClassNone, "off", "on");
|
|
} else {
|
|
createDiscovery("sensor",
|
|
discovery_topic.c_str(), entity_name.c_str(), unique_id.c_str(),
|
|
will_Topic, prop.value()["name"], value_template.c_str(),
|
|
"", "", prop.value()["unit"],
|
|
0, "", "", false, "",
|
|
model.c_str(), brand.c_str(), model_id.c_str(), macWOdots.c_str(), false,
|
|
stateClassMeasurement);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (p->sensorModel_id > BLEconectable::id::MIN &&
|
|
p->sensorModel_id < BLEconectable::id::MAX ||
|
|
p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::HHCCJCY01HHCC) {
|
|
|
|
if (p->sensorModel_id == BLEconectable::id::DT24_BLE) {
|
|
DT24Discovery(macWOdots.c_str(), "DT24-BLE");
|
|
}
|
|
if (p->sensorModel_id == BLEconectable::id::LYWSD03MMC) {
|
|
LYWSD03MMCDiscovery(macWOdots.c_str(), "LYWSD03MMC");
|
|
}
|
|
if (p->sensorModel_id == BLEconectable::id::MHO_C401) {
|
|
MHO_C401Discovery(macWOdots.c_str(), "MHO-C401");
|
|
}
|
|
if (p->sensorModel_id == BLEconectable::id::XMWSDJ04MMC) {
|
|
XMWSDJ04MMCDiscovery(macWOdots.c_str(), "XMWSDJ04MMC");
|
|
}
|
|
if (p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::HHCCJCY01HHCC) {
|
|
HHCCJCY01HHCCDiscovery(macWOdots.c_str(), "HHCCJCY01HHCC");
|
|
}
|
|
} else {
|
|
Log.trace(F("Device UNKNOWN_MODEL %s" CR), p->macAdr);
|
|
}
|
|
p->isDisc = true;
|
|
}
|
|
} else {
|
|
Log.trace(F("Device already discovered or that doesn't require discovery %s" CR), p->macAdr);
|
|
}
|
|
}
|
|
}
|
|
# endif
|
|
|
|
void PublishDeviceData(JsonObject& BLEdata, bool processBLEData) {
|
|
if (abs((int)BLEdata["rssi"] | 0) < abs(BTConfig.minRssi)) {
|
|
if (processBLEData) process_bledata(BLEdata);
|
|
if (!BTConfig.pubOnlySensors || BLEdata.containsKey("model") || BLEdata.containsKey("distance")) {
|
|
RemoveJsonPropertyIf(BLEdata, "servicedatauuid", !BTConfig.pubServiceDataUUID && BLEdata.containsKey("model"));
|
|
RemoveJsonPropertyIf(BLEdata, "servicedata", !BTConfig.pubKnownServiceData && BLEdata.containsKey("model"));
|
|
RemoveJsonPropertyIf(BLEdata, "manufacturerdata", !BTConfig.pubKnownManufData && BLEdata.containsKey("model"));
|
|
pubBT(BLEdata);
|
|
} else {
|
|
RemoveJsonPropertyIf(BLEdata, "servicedata", !BTConfig.pubUnknownServiceData);
|
|
RemoveJsonPropertyIf(BLEdata, "manufacturerdata", !BTConfig.pubUnknownManufData && BLEdata.containsKey("model"));
|
|
}
|
|
} else if (BLEdata.containsKey("distance")) {
|
|
pubBT(BLEdata);
|
|
} else {
|
|
Log.trace(F("Low rssi, device filtered" CR));
|
|
}
|
|
}
|
|
|
|
void process_bledata(JsonObject& BLEdata) {
|
|
const char* mac = BLEdata["id"].as<const char*>();
|
|
int model_id = BTConfig.extDecoderEnable ? -1 : decoder.decodeBLEJson(BLEdata);
|
|
int mac_type = BLEdata["mac_type"].as<int>();
|
|
if (model_id >= 0) {
|
|
Log.trace(F("Decoder found device: %s" CR), BLEdata["model_id"].as<const char*>());
|
|
if (model_id == TheengsDecoder::BLE_ID_NUM::HHCCJCY01HHCC) {
|
|
createOrUpdateDevice(mac, device_flags_connect, model_id, mac_type);
|
|
} else {
|
|
createOrUpdateDevice(mac, device_flags_init, model_id, mac_type);
|
|
}
|
|
} else {
|
|
if (BLEdata.containsKey("name")) {
|
|
std::string name = BLEdata["name"];
|
|
if (name.compare("LYWSD03MMC") == 0)
|
|
model_id = BLEconectable::id::LYWSD03MMC;
|
|
else if (name.compare("DT24-BLE") == 0)
|
|
model_id = BLEconectable::id::DT24_BLE;
|
|
else if (name.compare("MHO-C401") == 0)
|
|
model_id = BLEconectable::id::MHO_C401;
|
|
else if (name.compare("XMWSDJ04MMC") == 0)
|
|
model_id = BLEconectable::id::XMWSDJ04MMC;
|
|
|
|
if (model_id > 0) {
|
|
Log.trace(F("Connectable device found: %s" CR), name.c_str());
|
|
createOrUpdateDevice(mac, device_flags_connect, model_id, mac_type);
|
|
}
|
|
} else if (BTConfig.extDecoderEnable && model_id < 0 && BLEdata.containsKey("servicedata")) {
|
|
const char* service_data = (const char*)(BLEdata["servicedata"] | "");
|
|
if (strstr(service_data, "209800") != NULL) {
|
|
model_id == TheengsDecoder::BLE_ID_NUM::HHCCJCY01HHCC;
|
|
Log.trace(F("Connectable device found: HHCCJCY01HHCC" CR));
|
|
createOrUpdateDevice(mac, device_flags_connect, model_id, mac_type);
|
|
}
|
|
}
|
|
}
|
|
if (!BTConfig.extDecoderEnable && model_id < 0) {
|
|
Log.trace(F("No device found " CR));
|
|
}
|
|
}
|
|
|
|
void hass_presence(JsonObject& HomePresence) {
|
|
int BLErssi = HomePresence["rssi"];
|
|
Log.trace(F("BLErssi %d" CR), BLErssi);
|
|
int txPower = HomePresence["txpower"] | 0;
|
|
if (txPower >= 0)
|
|
txPower = -59;
|
|
Log.trace(F("TxPower: %d" CR), txPower);
|
|
double ratio = BLErssi * 1.0 / txPower;
|
|
double distance;
|
|
if (ratio < 1.0) {
|
|
distance = pow(ratio, 10);
|
|
} else {
|
|
distance = (0.89976) * pow(ratio, 7.7095) + 0.111;
|
|
}
|
|
HomePresence["distance"] = distance;
|
|
Log.trace(F("Ble distance %D" CR), distance);
|
|
}
|
|
|
|
void BTforceScan() {
|
|
if (!ProcessLock) {
|
|
BTtoMQTT();
|
|
Log.trace(F("Scan done" CR));
|
|
if (BTConfig.bleConnect)
|
|
BLEconnect();
|
|
} else {
|
|
Log.trace(F("Cannot launch scan due to other process running" CR));
|
|
}
|
|
}
|
|
|
|
void immediateBTAction(void* pvParameters) {
|
|
if (BLEactions.size()) {
|
|
|
|
ProcessLock = true;
|
|
NimBLEScan* pScan = NimBLEDevice::getScan();
|
|
if (pScan->isScanning()) {
|
|
pScan->stop();
|
|
}
|
|
|
|
if (xSemaphoreTake(semaphoreBLEOperation, pdMS_TO_TICKS(5000)) == pdTRUE) {
|
|
|
|
std::vector<BLEdevice*> dev_swap;
|
|
dev_swap.push_back(getDeviceByMac(BLEactions.back().addr));
|
|
std::swap(devices, dev_swap);
|
|
|
|
std::vector<BLEAction> act_swap;
|
|
act_swap.push_back(BLEactions.back());
|
|
BLEactions.pop_back();
|
|
std::swap(BLEactions, act_swap);
|
|
|
|
|
|
ProcessLock = false;
|
|
BLEconnect();
|
|
|
|
std::swap(devices, dev_swap);
|
|
std::swap(BLEactions, act_swap);
|
|
|
|
|
|
if ((!(scanCount % BTConfig.BLEscanBeforeConnect) || scanCount == 1) && BTConfig.bleConnect)
|
|
BLEconnect();
|
|
xSemaphoreGive(semaphoreBLEOperation);
|
|
} else {
|
|
Log.error(F("BLE busy - command not sent" CR));
|
|
JsonObject result = getBTJsonObject();
|
|
result["id"] = BLEactions.back().addr;
|
|
result["success"] = false;
|
|
pubBT(result);
|
|
BLEactions.pop_back();
|
|
ProcessLock = false;
|
|
}
|
|
}
|
|
vTaskDelete(NULL);
|
|
}
|
|
|
|
void startBTActionTask() {
|
|
TaskHandle_t th;
|
|
xTaskCreatePinnedToCore(
|
|
immediateBTAction,
|
|
"imActTask",
|
|
5120,
|
|
NULL,
|
|
3,
|
|
&th,
|
|
1);
|
|
}
|
|
|
|
void MQTTtoBTAction(JsonObject& BTdata) {
|
|
BLEAction action;
|
|
memset(&action, 0, sizeof(BLEAction));
|
|
if (BTdata.containsKey("SBS1")) {
|
|
strcpy(action.addr, (const char*)BTdata["mac"]);
|
|
action.write = true;
|
|
action.value = BTdata["SBS1"].as<std::string>();
|
|
action.ttl = 1;
|
|
createOrUpdateDevice(action.addr, device_flags_connect,
|
|
TheengsDecoder::BLE_ID_NUM::SBS1, 1);
|
|
BLEactions.push_back(action);
|
|
startBTActionTask();
|
|
return;
|
|
}
|
|
|
|
action.ttl = BTdata.containsKey("ttl") ? (uint8_t)BTdata["ttl"] : 1;
|
|
action.addr_type = BTdata.containsKey("mac_type") ? BTdata["mac_type"].as<int>() : 0;
|
|
action.value_type = BLE_VAL_STRING;
|
|
if (BTdata.containsKey("value_type")) {
|
|
String vt = BTdata["value_type"];
|
|
vt.toUpperCase();
|
|
if (vt == "HEX")
|
|
action.value_type = BLE_VAL_HEX;
|
|
else if (vt == "INT")
|
|
action.value_type = BLE_VAL_INT;
|
|
else if (vt == "FLOAT")
|
|
action.value_type = BLE_VAL_FLOAT;
|
|
else if (vt != "STRING") {
|
|
Log.error(F("BLE value type invalid %s" CR), vt.c_str());
|
|
return;
|
|
}
|
|
}
|
|
|
|
Log.trace(F("BLE ACTION TTL = %u" CR), action.ttl);
|
|
action.complete = false;
|
|
if (BTdata.containsKey("ble_write_address") &&
|
|
BTdata.containsKey("ble_write_service") &&
|
|
BTdata.containsKey("ble_write_char") &&
|
|
BTdata.containsKey("ble_write_value")) {
|
|
strcpy(action.addr, (const char*)BTdata["ble_write_address"]);
|
|
action.service = NimBLEUUID((const char*)BTdata["ble_write_service"]);
|
|
action.characteristic = NimBLEUUID((const char*)BTdata["ble_write_char"]);
|
|
action.value = std::string((const char*)BTdata["ble_write_value"]);
|
|
action.write = true;
|
|
Log.trace(F("BLE ACTION Write" CR));
|
|
} else if (BTdata.containsKey("ble_read_address") &&
|
|
BTdata.containsKey("ble_read_service") &&
|
|
BTdata.containsKey("ble_read_char")) {
|
|
strcpy(action.addr, (const char*)BTdata["ble_read_address"]);
|
|
action.service = NimBLEUUID((const char*)BTdata["ble_read_service"]);
|
|
action.characteristic = NimBLEUUID((const char*)BTdata["ble_read_char"]);
|
|
action.write = false;
|
|
Log.trace(F("BLE ACTION Read" CR));
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
createOrUpdateDevice(action.addr, device_flags_connect,
|
|
TheengsDecoder::BLE_ID_NUM::UNKNOWN_MODEL,
|
|
action.addr_type);
|
|
|
|
BLEactions.push_back(action);
|
|
if (BTdata.containsKey("immediate") && BTdata["immediate"].as<bool>()) {
|
|
startBTActionTask();
|
|
}
|
|
}
|
|
|
|
void MQTTtoBT(char* topicOri, JsonObject& BTdata) {
|
|
if (cmpToMainTopic(topicOri, subjectMQTTtoBTset)) {
|
|
Log.trace(F("MQTTtoBT json set" CR));
|
|
|
|
|
|
bool WorBupdated;
|
|
WorBupdated = updateWorB(BTdata, true);
|
|
WorBupdated |= updateWorB(BTdata, false);
|
|
|
|
if (WorBupdated) {
|
|
if (xSemaphoreTake(semaphoreCreateOrUpdateDevice, pdMS_TO_TICKS(1000)) == pdTRUE) {
|
|
dumpDevices();
|
|
xSemaphoreGive(semaphoreCreateOrUpdateDevice);
|
|
}
|
|
}
|
|
|
|
|
|
if (BTdata.containsKey("interval") && BTdata["interval"] == 0) {
|
|
Log.notice(F("BLE forced scan" CR));
|
|
atomic_store_explicit(&forceBTScan, 1, ::memory_order_seq_cst);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (BTdata.containsKey("init") && BTdata["init"].as<bool>()) {
|
|
|
|
BTConfig_init();
|
|
} else if (BTdata.containsKey("load") && BTdata["load"].as<bool>()) {
|
|
|
|
BTConfig_load();
|
|
}
|
|
|
|
|
|
BTConfig_fromJson(BTdata);
|
|
|
|
if (BTdata.containsKey("lowpowermode")) {
|
|
changelowpowermode((int)BTdata["lowpowermode"]);
|
|
}
|
|
|
|
MQTTtoBTAction(BTdata);
|
|
}
|
|
}
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayGFSunInverter.ino"
|
|
# 26 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayGFSunInverter.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZgatewayGFSunInverter
|
|
|
|
GfSun2000 GF = GfSun2000();
|
|
|
|
void GFSunInverterDataHandler(GfSun2000Data data) {
|
|
StaticJsonDocument<2 * JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject jdata = jsonBuffer.to<JsonObject>();
|
|
|
|
jdata["device_id"] = (char*)data.deviceID;
|
|
Log.trace(F("Device ID : %s\n" CR), data.deviceID);
|
|
jdata["ac_voltage"] = data.ACVoltage;
|
|
Log.trace(F("AC Voltage : %.1f\tV\n" CR), data.ACVoltage);
|
|
jdata["dc_voltage"] = data.DCVoltage;
|
|
Log.trace(F("DC Voltage : %.1f\tV\n" CR), data.DCVoltage);
|
|
jdata["power"] = data.averagePower;
|
|
Log.trace(F("Output Power : %.1f\tW (5min avg)\n" CR), data.averagePower);
|
|
jdata["c_energy"] = data.customEnergyCounter;
|
|
Log.trace(F("Custom Energy : %.1f\tkW/h (can be reseted)\n" CR), data.customEnergyCounter);
|
|
jdata["t_energy"] = data.totalEnergyCounter;
|
|
Log.trace(F("Total Energy : %.1f\tkW/h\n" CR), data.totalEnergyCounter);
|
|
|
|
# ifdef GFSUNINVERTER_DEVEL
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer2;
|
|
JsonObject jregister = jsonBuffer2.to<JsonObject>();
|
|
char buffer[4];
|
|
std::map<int16_t, int16_t>::iterator itr;
|
|
for (itr = data.modbusRegistry.begin(); itr != data.modbusRegistry.end(); ++itr) {
|
|
Log.notice("%d: %d\n", itr->first, itr->second);
|
|
sprintf(buffer, "%d", itr->first);
|
|
jregister[buffer] = itr->second;
|
|
}
|
|
jdata["register"] = jregister;
|
|
# endif
|
|
pub(subjectRFtoMQTT, jdata);
|
|
}
|
|
|
|
void GFSunInverterErrorHandler(int errorId, char* errorMessage) {
|
|
char buffer[50];
|
|
sprintf(buffer, "Error response: %02X - %s\n", errorId, errorMessage);
|
|
Log.error(buffer);
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject jdata = jsonBuffer.to<JsonObject>();
|
|
jdata["status"] = "error";
|
|
jdata["msg"] = errorMessage;
|
|
jdata["id"] = errorId;
|
|
pub(subjectRFtoMQTT, jdata);
|
|
}
|
|
|
|
void setupGFSunInverter() {
|
|
GF.setup(Serial2);
|
|
GF.setDataHandler(GFSunInverterDataHandler);
|
|
GF.setErrorHandler(GFSunInverterErrorHandler);
|
|
Log.trace(F("ZgatewayGFSunInverter setup done " CR));
|
|
}
|
|
|
|
void ZgatewayGFSunInverterMQTT() {
|
|
GF.readData();
|
|
delay(GFSUNINVERTER_DELAY);
|
|
}
|
|
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayIR.ino"
|
|
# 28 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayIR.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZgatewayIR
|
|
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
# include <IRrecv.h>
|
|
# include <IRremoteESP8266.h>
|
|
# include <IRsend.h>
|
|
# include <IRutils.h>
|
|
# ifdef DumpMode
|
|
IRrecv irrecv(IR_RECEIVER_GPIO, 1024, 15U, true);
|
|
# else
|
|
IRrecv irrecv(IR_RECEIVER_GPIO);
|
|
# endif
|
|
IRsend irsend(IR_EMITTER_GPIO, IR_EMITTER_INVERTED);
|
|
# else
|
|
# include <IRremote.h>
|
|
IRrecv irrecv(IR_RECEIVER_GPIO);
|
|
IRsend irsend;
|
|
# endif
|
|
|
|
|
|
# ifndef NEC_BITS
|
|
#define NEC_BITS 32U
|
|
# endif
|
|
# ifndef SAMSUNG_BITS
|
|
#define SAMSUNG_BITS 32U
|
|
# endif
|
|
# ifndef SHARP_BITS
|
|
#define SHARP_ADDRESS_BITS 5U
|
|
#define SHARP_COMMAND_BITS 8U
|
|
#define SHARP_BITS (SHARP_ADDRESS_BITS + SHARP_COMMAND_BITS + 2)
|
|
# endif
|
|
# ifndef RC5_BITS
|
|
#define RC5_RAW_BITS 14U
|
|
#define RC5_BITS RC5_RAW_BITS - 2U
|
|
# endif
|
|
# ifndef DISH_BITS
|
|
#define DISH_BITS 16U
|
|
# endif
|
|
# ifndef SONY_20_BITS
|
|
#define SONY_20_BITS 20
|
|
# endif
|
|
# ifndef SONY_12_BITS
|
|
#define SONY_12_BITS 12U
|
|
# endif
|
|
# ifndef LG_BITS
|
|
#define LG_BITS 28U
|
|
# endif
|
|
# ifndef WHYNTER_BITS
|
|
#define WHYNTER_BITS 32U
|
|
# endif
|
|
|
|
|
|
uint64_t getUInt64fromHex(char const* str) {
|
|
uint64_t result = 0;
|
|
uint16_t offset = 0;
|
|
|
|
if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) offset = 2;
|
|
for (; isxdigit((unsigned char)str[offset]); offset++) {
|
|
char c = str[offset];
|
|
result *= 16;
|
|
if (isdigit(c))
|
|
result += c - '0';
|
|
else if (isupper(c))
|
|
result += c - 'A' + 10;
|
|
else
|
|
result += c - 'a' + 10;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void setupIR() {
|
|
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
irsend.begin();
|
|
# endif
|
|
|
|
irrecv.enableIRIn();
|
|
|
|
Log.notice(F("IR_EMITTER_GPIO: %d " CR), IR_EMITTER_GPIO);
|
|
Log.notice(F("IR_RECEIVER_GPIO: %d " CR), IR_RECEIVER_GPIO);
|
|
Log.trace(F("ZgatewayIR setup done " CR));
|
|
}
|
|
|
|
void IRtoMQTT() {
|
|
decode_results results;
|
|
|
|
if (irrecv.decode(&results)) {
|
|
Log.trace(F("Creating IR buffer" CR));
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject IRdata = jsonBuffer.to<JsonObject>();
|
|
|
|
Log.trace(F("Rcv. IR" CR));
|
|
# ifdef ESP32
|
|
Log.trace(F("IR Task running on core :%d" CR), xPortGetCoreID());
|
|
# endif
|
|
IRdata["value"] = (SIGNAL_SIZE_UL_ULL)(results.value);
|
|
IRdata["protocol"] = (int)(results.decode_type);
|
|
IRdata["bits"] = (int)(results.bits);
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
String hex = resultToHexidecimal(&results);
|
|
IRdata["hex"] = (const char*)hex.c_str();
|
|
String protocol = typeToString(results.decode_type, false);
|
|
IRdata["protocol_name"] = (const char*)protocol.c_str();
|
|
# endif
|
|
String rawCode = "";
|
|
|
|
for (uint16_t i = 1; i < results.rawlen; i++) {
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
if (i % 100 == 0)
|
|
yield();
|
|
rawCode = rawCode + (results.rawbuf[i] * RAWTICK);
|
|
# else
|
|
rawCode = rawCode + (results.rawbuf[i] * USECPERTICK);
|
|
# endif
|
|
if (i < results.rawlen - 1)
|
|
rawCode = rawCode + ",";
|
|
}
|
|
IRdata["raw"] = rawCode;
|
|
|
|
# ifdef RawDirectForward
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
uint16_t rawsend[results.rawlen];
|
|
for (uint16_t i = 1; i < results.rawlen; i++) {
|
|
if (i % 100 == 0)
|
|
yield();
|
|
# else
|
|
unsigned int rawsend[results.rawlen];
|
|
for (int i = 1; i < results.rawlen; i++) {
|
|
# endif
|
|
rawsend[i] = results.rawbuf[i];
|
|
}
|
|
irsend.sendRaw(rawsend, results.rawlen, RawFrequency);
|
|
Log.trace(F("raw redirected" CR));
|
|
# endif
|
|
irrecv.resume();
|
|
SIGNAL_SIZE_UL_ULL MQTTvalue = IRdata["value"].as<SIGNAL_SIZE_UL_ULL>();
|
|
|
|
if ((pubIRunknownPrtcl == false && IRdata["protocol"].as<int>() == -1)) {
|
|
Log.notice(F("--no pub unknwn prt--" CR));
|
|
} else if (!isAduplicateSignal(MQTTvalue) && MQTTvalue != 0) {
|
|
Log.trace(F("Adv data IRtoMQTT" CR));
|
|
pub(subjectIRtoMQTT, IRdata);
|
|
Log.trace(F("Store val: %D" CR), MQTTvalue);
|
|
storeSignalValue(MQTTvalue);
|
|
if (repeatIRwMQTT) {
|
|
Log.trace(F("Pub. IR for rpt" CR));
|
|
pubMQTT(subjectForwardMQTTtoIR, MQTTvalue);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool sendIdentifiedProtocol(const char* protocol_name, SIGNAL_SIZE_UL_ULL data, const char* hex, unsigned int valueBITS, uint16_t valueRPT);
|
|
|
|
# if jsonReceiving
|
|
void MQTTtoIR(char* topicOri, JsonObject& IRdata) {
|
|
if (cmpToMainTopic(topicOri, subjectMQTTtoIR)) {
|
|
Log.trace(F("MQTTtoIR json" CR));
|
|
uint64_t data = IRdata["value"];
|
|
const char* raw = IRdata["raw"];
|
|
const char* hex = IRdata["hex"];
|
|
if (hex) {
|
|
Log.trace(F("hex: %s" CR), hex);
|
|
data = getUInt64fromHex(hex);
|
|
}
|
|
if (data != 0 || raw) {
|
|
Log.trace(F("MQTTtoIR value || raw detected" CR));
|
|
bool signalSent = false;
|
|
const char* protocol_name = IRdata["protocol_name"];
|
|
unsigned int valueBITS = IRdata["bits"] | 0;
|
|
uint16_t valueRPT = IRdata["repeat"] | repeatIRwNumber;
|
|
|
|
if (raw) {
|
|
Log.trace(F("Raw: %s" CR), raw);
|
|
unsigned int s = strlen(raw);
|
|
|
|
int count = 0;
|
|
for (int i = 0; i < s; i++) {
|
|
if (raw[i] == ',') {
|
|
count++;
|
|
}
|
|
}
|
|
# ifdef IR_GC
|
|
if (strcmp(protocol_name, "GC") == 0) {
|
|
Log.trace(F("GC" CR));
|
|
|
|
uint16_t GC[count + 1];
|
|
String value = "";
|
|
int j = 0;
|
|
for (int i = 0; i < s; i++) {
|
|
if (raw[i] != ',') {
|
|
value = value + String(raw[i]);
|
|
}
|
|
if ((raw[i] == ',') || (i == s - 1)) {
|
|
GC[j] = value.toInt();
|
|
value = "";
|
|
j++;
|
|
}
|
|
}
|
|
irsend.sendGC(GC, j);
|
|
signalSent = true;
|
|
}
|
|
# endif
|
|
# ifdef IR_RAW
|
|
if (strcmp(protocol_name, "Raw") == 0) {
|
|
Log.trace(F("Raw" CR));
|
|
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
uint16_t Raw[count + 1];
|
|
# else
|
|
unsigned int Raw[count + 1];
|
|
# endif
|
|
String value = "";
|
|
int j = 0;
|
|
for (int i = 0; i < s; i++) {
|
|
if (raw[i] != ',') {
|
|
value = value + String(raw[i]);
|
|
}
|
|
if ((raw[i] == ',') || (i == s - 1)) {
|
|
Raw[j] = value.toInt();
|
|
value = "";
|
|
j++;
|
|
}
|
|
}
|
|
irsend.sendRaw(Raw, j, RawFrequency);
|
|
signalSent = true;
|
|
}
|
|
# endif
|
|
} else if (protocol_name && (strcmp(protocol_name, "NEC") != 0)) {
|
|
Log.trace(F("Using Identified Protocol: %s bits: %d repeat: %d" CR), protocol_name, valueBITS, valueRPT);
|
|
signalSent = sendIdentifiedProtocol(protocol_name, data, hex, valueBITS, valueRPT);
|
|
} else {
|
|
Log.trace(F("Using NEC protocol" CR));
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = NEC_BITS;
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
irsend.sendNEC(data, valueBITS, valueRPT);
|
|
# else
|
|
for (int i = 0; i <= valueRPT; i++)
|
|
irsend.sendNEC(data, valueBITS);
|
|
# endif
|
|
signalSent = true;
|
|
}
|
|
if (signalSent) {
|
|
Log.notice(F("MQTTtoIR OK" CR));
|
|
pub(subjectGTWIRtoMQTT, IRdata);
|
|
}
|
|
irrecv.enableIRIn();
|
|
} else {
|
|
Log.error(F("MQTTtoIR failed json read" CR));
|
|
}
|
|
}
|
|
}
|
|
# endif
|
|
|
|
bool sendIdentifiedProtocol(const char* protocol_name, SIGNAL_SIZE_UL_ULL data, const char* hex, unsigned int valueBITS, uint16_t valueRPT) {
|
|
uint8_t dataarray[valueBITS];
|
|
if (hex) {
|
|
const char* ptr = NULL;
|
|
(strstr(hex, "0x") != NULL) ? ptr = hex += 2 : ptr = hex;
|
|
for (int i = 0; i < sizeof dataarray / sizeof *dataarray; i++) {
|
|
sscanf(ptr, "%2hhx", &dataarray[i]);
|
|
ptr += 2;
|
|
}
|
|
for (int i = 0; i < valueBITS; i++) {
|
|
Log.trace(F("%x"), dataarray[i]);
|
|
}
|
|
}
|
|
# ifdef IR_WHYNTER
|
|
if (strcmp(protocol_name, "WHYNTER") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = WHYNTER_BITS;
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
irsend.sendWhynter(data, valueBITS, valueRPT);
|
|
# else
|
|
for (int i = 0; i <= valueRPT; i++)
|
|
irsend.sendWhynter(data, valueBITS);
|
|
# endif
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_LG
|
|
if (strcmp(protocol_name, "LG") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = LG_BITS;
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
irsend.sendLG(data, valueBITS, valueRPT);
|
|
# else
|
|
for (int i = 0; i <= valueRPT; i++)
|
|
irsend.sendLG(data, valueBITS);
|
|
# endif
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_SONY
|
|
if (strcmp(protocol_name, "SONY") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
if (valueBITS == 0)
|
|
valueBITS = SONY_20_BITS;
|
|
irsend.sendSony(data, valueBITS, valueRPT);
|
|
# else
|
|
if (valueBITS == 0)
|
|
valueBITS = SONY_12_BITS;
|
|
for (int i = 0; i <= valueRPT; i++)
|
|
irsend.sendSony(data, valueBITS);
|
|
# endif
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_DISH
|
|
if (strcmp(protocol_name, "DISH") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = DISH_BITS;
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
irsend.sendDISH(data, valueBITS, valueRPT);
|
|
# else
|
|
for (int i = 0; i <= valueRPT; i++)
|
|
irsend.sendDISH(data, valueBITS);
|
|
# endif
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_RC5
|
|
if (strcmp(protocol_name, "RC5") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = RC5_BITS;
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
irsend.sendRC5(data, valueBITS, valueRPT);
|
|
# else
|
|
for (int i = 0; i <= valueRPT; i++)
|
|
irsend.sendRC5(data, valueBITS);
|
|
# endif
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_RC6
|
|
if (strcmp(protocol_name, "RC6") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = RC6_MODE0_BITS;
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
irsend.sendRC6(data, valueBITS, valueRPT);
|
|
# else
|
|
for (int i = 0; i <= valueRPT; i++)
|
|
irsend.sendRC6(data, valueBITS);
|
|
# endif
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_SHARP
|
|
if (strcmp(protocol_name, "SHARP") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = SHARP_BITS;
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
irsend.sendSharpRaw(data, valueBITS, valueRPT);
|
|
# else
|
|
for (int i = 0; i <= valueRPT; i++)
|
|
irsend.sendSharpRaw(data, valueBITS);
|
|
# endif
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_SAMSUNG
|
|
if (strcmp(protocol_name, "SAMSUNG") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = SAMSUNG_BITS;
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
irsend.sendSAMSUNG(data, valueBITS, valueRPT);
|
|
# else
|
|
for (int i = 0; i <= valueRPT; i++)
|
|
irsend.sendSAMSUNG(data, valueBITS);
|
|
# endif
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_JVC
|
|
if (strcmp(protocol_name, "JVC") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = JVC_BITS;
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
irsend.sendJVC(data, valueBITS, valueRPT);
|
|
# else
|
|
for (int i = 0; i <= valueRPT; i++)
|
|
irsend.sendJVC(data, valueBITS);
|
|
# endif
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_PANASONIC
|
|
if (strcmp(protocol_name, "PANASONIC") == 0) {
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = PANASONIC_BITS;
|
|
irsend.sendPanasonic(PanasonicAddress, data, valueBITS, valueRPT);
|
|
# else
|
|
for (int i = 0; i <= valueRPT; i++)
|
|
irsend.sendPanasonic(PanasonicAddress, data);
|
|
# endif
|
|
return true;
|
|
}
|
|
# endif
|
|
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
# ifdef IR_COOLIX
|
|
if (strcmp(protocol_name, "COOLIX") == 0) {
|
|
Log.trace(F("Sending %s:" CR), protocol_name);
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kCoolixBits;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kCoolixDefaultRepeat);
|
|
irsend.sendCOOLIX(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_RCMM
|
|
if (strcmp(protocol_name, "RCMM") == 0) {
|
|
Log.trace(F("Sending %s:" CR), protocol_name);
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kRCMMBits;
|
|
irsend.sendRCMM(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_DENON
|
|
if (strcmp(protocol_name, "DENON") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = DENON_BITS;
|
|
irsend.sendDenon(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_GICABLE
|
|
if (strcmp(protocol_name, "GICABLE") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kGicableBits;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kGicableMinRepeat);
|
|
irsend.sendGICable(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_SHERWOOD
|
|
if (strcmp(protocol_name, "SHERWOOD") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kSherwoodBits;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kSherwoodMinRepeat);
|
|
irsend.sendSherwood(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_MITSUBISHI
|
|
if (strcmp(protocol_name, "MITSUBISHI") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kMitsubishiBits;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kMitsubishiMinRepeat);
|
|
irsend.sendMitsubishi(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_NIKAI
|
|
if (strcmp(protocol_name, "NIKAI") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kNikaiBits;
|
|
irsend.sendNikai(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_MIDEA
|
|
if (strcmp(protocol_name, "MIDEA") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kMideaBits;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kMideaMinRepeat);
|
|
irsend.sendMidea(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_MAGIQUEST
|
|
if (strcmp(protocol_name, "MAGIQUEST") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kMagiquestBits;
|
|
irsend.sendMagiQuest(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_LASERTAG
|
|
if (strcmp(protocol_name, "LASERTAG") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kLasertagBits;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kLasertagMinRepeat);
|
|
irsend.sendLasertag(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_CARRIER_AC
|
|
if (strcmp(protocol_name, "CARRIER_AC") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kCarrierAcBits;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kCarrierAcMinRepeat);
|
|
irsend.sendCarrierAC(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_MITSUBISHI2
|
|
if (strcmp(protocol_name, "MITSUBISHI2") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kMitsubishiBits;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kMitsubishiMinRepeat);
|
|
irsend.sendMitsubishi2(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_AIWA_RC_T501
|
|
if (strcmp(protocol_name, "AIWA_RC_T501") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kAiwaRcT501Bits;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kAiwaRcT501MinRepeats);
|
|
irsend.sendAiwaRCT501(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_DAIKIN
|
|
if (strcmp(protocol_name, "DAIKIN") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kDaikinStateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kDaikinDefaultRepeat);
|
|
irsend.sendDaikin(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_KELVINATOR
|
|
if (strcmp(protocol_name, "KELVINATOR") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kKelvinatorStateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kKelvinatorDefaultRepeat);
|
|
irsend.sendKelvinator(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_MITSUBISHI_AC
|
|
if (strcmp(protocol_name, "MITSUBISHI_AC") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kMitsubishiACStateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kMitsubishiACMinRepeat);
|
|
irsend.sendMitsubishiAC(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_SANYO
|
|
if (strcmp(protocol_name, "SANYOLC7461") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kSanyoLC7461Bits;
|
|
irsend.sendSanyoLC7461(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_GREE
|
|
if (strcmp(protocol_name, "GREE") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kGreeStateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kGreeDefaultRepeat);
|
|
irsend.sendGree(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_ARGO
|
|
if (strcmp(protocol_name, "ARGO") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kArgoStateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kArgoDefaultRepeat);
|
|
irsend.sendArgo(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_TROTEC
|
|
if (strcmp(protocol_name, "TROTEC") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kTrotecStateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kTrotecDefaultRepeat);
|
|
irsend.sendTrotec(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_TOSHIBA_AC
|
|
if (strcmp(protocol_name, "TOSHIBA_AC") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kToshibaACBits;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kToshibaACMinRepeat);
|
|
irsend.sendToshibaAC(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_FUJITSU_AC
|
|
if (strcmp(protocol_name, "FUJITSU_AC") == 0) {
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kFujitsuAcMinRepeat);
|
|
irsend.sendFujitsuAC(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_HAIER_AC
|
|
if (strcmp(protocol_name, "HAIER_AC") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kHaierACStateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kHaierAcDefaultRepeat);
|
|
irsend.sendHaierAC(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_HITACHI_AC
|
|
if (strcmp(protocol_name, "HITACHI_AC") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kHitachiAcStateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kHitachiAcDefaultRepeat);
|
|
irsend.sendHitachiAC(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_HITACHI_AC1
|
|
if (strcmp(protocol_name, "HITACHI_AC1") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kHitachiAc1StateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kHitachiAcDefaultRepeat);
|
|
irsend.sendHitachiAC1(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_HITACHI_AC2
|
|
if (strcmp(protocol_name, "HITACHI_AC2") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kHitachiAc2StateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kHitachiAcDefaultRepeat);
|
|
irsend.sendHitachiAC2(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_HAIER_AC_YRW02
|
|
if (strcmp(protocol_name, "HAIER_AC_YRW02") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kHaierACYRW02StateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kHaierAcYrw02DefaultRepeat);
|
|
irsend.sendHaierACYRW02(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_WHIRLPOOL_AC
|
|
if (strcmp(protocol_name, "WHIRLPOOL_AC") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kWhirlpoolAcStateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kWhirlpoolAcDefaultRepeat);
|
|
irsend.sendWhirlpoolAC(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_SAMSUNG_AC
|
|
if (strcmp(protocol_name, "SAMSUNG_AC") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kSamsungAcStateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kSamsungAcDefaultRepeat);
|
|
irsend.sendSamsungAC(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_LUTRON
|
|
if (strcmp(protocol_name, "LUTRON") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kLutronBits;
|
|
irsend.sendLutron(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_ELECTRA_AC
|
|
if (strcmp(protocol_name, "ELECTRA_AC") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kElectraAcStateLength;
|
|
irsend.sendElectraAC(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_PANASONIC_AC
|
|
if (strcmp(protocol_name, "PANASONIC_AC") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kPanasonicAcStateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kPanasonicAcDefaultRepeat);
|
|
irsend.sendPanasonicAC(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_PIONEER
|
|
if (strcmp(protocol_name, "PIONEER") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kPioneerBits;
|
|
irsend.sendPioneer(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_LG2
|
|
if (strcmp(protocol_name, "LG2") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kLgBits;
|
|
irsend.sendLG2(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_MWM
|
|
if (strcmp(protocol_name, "MWM") == 0) {
|
|
irsend.sendMWM(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_DAIKIN2
|
|
if (strcmp(protocol_name, "DAIKIN2") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kDaikin2StateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kDaikin2DefaultRepeat);
|
|
irsend.sendDaikin2(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_VESTEL_AC
|
|
if (strcmp(protocol_name, "VESTEL_AC") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kVestelAcBits;
|
|
irsend.sendVestelAc(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_SAMSUNG36
|
|
if (strcmp(protocol_name, "SAMSUNG36") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kSamsung36Bits;
|
|
irsend.sendSamsung36(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_TCL112AC
|
|
if (strcmp(protocol_name, "TCL112AC") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kTcl112AcStateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kTcl112AcDefaultRepeat);
|
|
irsend.sendTcl112Ac(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_TECO
|
|
if (strcmp(protocol_name, "TECO") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kTecoBits;
|
|
irsend.sendTeco(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_LEGOPF
|
|
if (strcmp(protocol_name, "LEGOPF") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kLegoPfBits;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kLegoPfMinRepeat);
|
|
irsend.sendLegoPf(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_MITSUBISHIHEAVY88
|
|
if (strcmp(protocol_name, "MITSUBISHIHEAVY88") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kMitsubishiHeavy88StateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kMitsubishiHeavy88MinRepeat);
|
|
irsend.sendMitsubishiHeavy88(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_MITSUBISHIHEAVY152
|
|
if (strcmp(protocol_name, "MITSUBISHIHEAVY152") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kMitsubishiHeavy152StateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kMitsubishiHeavy152MinRepeat);
|
|
irsend.sendMitsubishiHeavy152(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_DAIKIN216
|
|
if (strcmp(protocol_name, "DAIKIN216") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kDaikin216StateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kDaikin216DefaultRepeat);
|
|
irsend.sendDaikin216(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_SHARP_AC
|
|
if (strcmp(protocol_name, "SHARP_AC") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kSharpAcStateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kSharpAcDefaultRepeat);
|
|
irsend.sendSharpAc(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_GOODWEATHER
|
|
if (strcmp(protocol_name, "GOODWEATHER_AC") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kGoodweatherBits;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kGoodweatherMinRepeat);
|
|
irsend.sendGoodweather(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_INAX
|
|
if (strcmp(protocol_name, "INAX") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kInaxBits;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kInaxMinRepeat);
|
|
irsend.sendInax(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_DAIKIN160
|
|
if (strcmp(protocol_name, "DAIKIN160") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kDaikin160StateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kDaikin160DefaultRepeat);
|
|
irsend.sendDaikin160(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_NEOCLIMA
|
|
if (strcmp(protocol_name, "NEOCLIMA") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kNeoclimaStateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kNeoclimaMinRepeat);
|
|
irsend.sendNeoclima(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_DAIKIN176
|
|
if (strcmp(protocol_name, "DAIKIN176") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kDaikin176StateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kDaikin176DefaultRepeat);
|
|
irsend.sendDaikin176(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_DAIKIN128
|
|
if (strcmp(protocol_name, "DAIKIN128") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kDaikin128StateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kDaikin128DefaultRepeat);
|
|
irsend.sendDaikin128(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_AMCOR
|
|
if (strcmp(protocol_name, "AMCOR") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kAmcorStateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kAmcorDefaultRepeat);
|
|
irsend.sendAmcor(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_DAIKIN152
|
|
if (strcmp(protocol_name, "DAIKIN152") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kDaikin152StateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kDaikin152DefaultRepeat);
|
|
irsend.sendDaikin152(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_MITSUBISHI136
|
|
if (strcmp(protocol_name, "MITSUBISHI136") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kMitsubishi136StateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kMitsubishi136MinRepeat);
|
|
irsend.sendMitsubishi136(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_MITSUBISHI112
|
|
if (strcmp(protocol_name, "MITSUBISHI112") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kMitsubishi112StateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kMitsubishi112MinRepeat);
|
|
irsend.sendMitsubishi112(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_HITACHI_AC424
|
|
if (strcmp(protocol_name, "HITACHI_AC424") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kHitachiAc424StateLength;
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kHitachiAcDefaultRepeat);
|
|
irsend.sendHitachiAc424(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_SONY_38K
|
|
if (strcmp(protocol_name, "SONY_38K") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, (uint16_t)(kSonyMinRepeat + 1));
|
|
if (valueBITS == 0)
|
|
valueBITS = kSony20Bits;
|
|
irsend.sendSony38(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_EPSON
|
|
if (strcmp(protocol_name, "EPSON") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kEpsonMinRepeat);
|
|
if (valueBITS == 0)
|
|
valueBITS = kEpsonBits;
|
|
irsend.sendEpson(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_SYMPHONY
|
|
if (strcmp(protocol_name, "SYMPHONY") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kSymphonyDefaultRepeat);
|
|
if (valueBITS == 0)
|
|
valueBITS = kSymphonyBits;
|
|
irsend.sendSymphony(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_HITACHI_AC3
|
|
if (strcmp(protocol_name, "HITACHI_AC3") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kHitachiAcDefaultRepeat);
|
|
if (valueBITS == 0)
|
|
Log.error(F("For this protocol you should have a BIT number as there is no default one defined" CR));
|
|
irsend.sendHitachiAc3(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_DAIKIN64
|
|
if (strcmp(protocol_name, "DAIKIN64") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kDaikin64DefaultRepeat);
|
|
if (valueBITS == 0)
|
|
valueBITS = kDaikin64Bits;
|
|
irsend.sendDaikin64(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_AIRWELL
|
|
if (strcmp(protocol_name, "AIRWELL") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kAirwellMinRepeats);
|
|
if (valueBITS == 0)
|
|
valueBITS = kAirwellBits;
|
|
irsend.sendAirwell(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_DELONGHI_AC
|
|
if (strcmp(protocol_name, "DELONGHI_AC") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kDelonghiAcDefaultRepeat);
|
|
if (valueBITS == 0)
|
|
valueBITS = kDelonghiAcBits;
|
|
irsend.sendDelonghiAc(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_DOSHISHA
|
|
if (strcmp(protocol_name, "DOSHISHA") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kDoshishaBits;
|
|
irsend.sendDoshisha(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_CARRIER_AC40
|
|
if (strcmp(protocol_name, "CARRIER_AC40") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kCarrierAc40MinRepeat);
|
|
if (valueBITS == 0)
|
|
valueBITS = kCarrierAc40Bits;
|
|
irsend.sendCarrierAC40(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_CARRIER_AC64
|
|
if (strcmp(protocol_name, "CARRIER_AC64") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kCarrierAc64MinRepeat);
|
|
if (valueBITS == 0)
|
|
valueBITS = kCarrierAc64Bits;
|
|
irsend.sendCarrierAC64(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_HITACHI_AC344
|
|
if (strcmp(protocol_name, "HITACHI_AC344") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kHitachiAc344StateLength;
|
|
irsend.sendHitachiAc344(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_CORONA_AC
|
|
if (strcmp(protocol_name, "CORONA_AC") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kCoronaAcStateLength;
|
|
irsend.sendCoronaAc(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_MIDEA24
|
|
if (strcmp(protocol_name, "MIDEA24") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kMidea24MinRepeat);
|
|
if (valueBITS == 0)
|
|
valueBITS = kMidea24Bits;
|
|
irsend.sendMidea24(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_ZEPEAL
|
|
if (strcmp(protocol_name, "ZEPEAL") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kZepealMinRepeat);
|
|
if (valueBITS == 0)
|
|
valueBITS = kZepealBits;
|
|
irsend.sendZepeal(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_SANYO_AC
|
|
if (strcmp(protocol_name, "SANYO_AC") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kSanyoAcStateLength;
|
|
irsend.sendSanyoAc(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_VOLTAS
|
|
if (strcmp(protocol_name, "VOLTAS") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kVoltasStateLength;
|
|
irsend.sendVoltas(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_METZ
|
|
if (strcmp(protocol_name, "METZ") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kMetzMinRepeat);
|
|
if (valueBITS == 0)
|
|
valueBITS = kMetzBits;
|
|
irsend.sendMetz(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_TRANSCOLD
|
|
if (strcmp(protocol_name, "TRANSCOLD") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kTranscoldDefaultRepeat);
|
|
if (valueBITS == 0)
|
|
valueBITS = kTranscoldBits;
|
|
irsend.sendTranscold(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_TECHNIBEL_AC
|
|
if (strcmp(protocol_name, "TECHNIBELAC") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kTechnibelAcDefaultRepeat);
|
|
if (valueBITS == 0)
|
|
valueBITS = kTechnibelAcBits;
|
|
irsend.sendTechnibelAc(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_MIRAGE
|
|
if (strcmp(protocol_name, "MIRAGE") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kMirageMinRepeat);
|
|
if (valueBITS == 0)
|
|
valueBITS = kMirageStateLength;
|
|
irsend.sendMirage(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_ELITESCREENS
|
|
if (strcmp(protocol_name, "ELITESCREENS") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kEliteScreensDefaultRepeat);
|
|
if (valueBITS == 0)
|
|
valueBITS = kEliteScreensBits;
|
|
irsend.sendElitescreens(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_PANASONIC_AC32
|
|
if (strcmp(protocol_name, "PANASONIC_AC32") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kPioneerBits;
|
|
irsend.sendPanasonicAC32(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_MILESTAG2
|
|
if (strcmp(protocol_name, "MILESTAG2") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueRPT == repeatIRwNumber)
|
|
valueRPT = std::max(valueRPT, kMilesMinRepeat);
|
|
if (valueBITS == 0)
|
|
valueBITS = kMilesTag2ShotBits;
|
|
irsend.sendMilestag2(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_ECOCLIM
|
|
if (strcmp(protocol_name, "ECOCLIM") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kEcoclimBits;
|
|
irsend.sendEcoclim(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_XMP
|
|
if (strcmp(protocol_name, "XMP") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kXmpBits;
|
|
irsend.sendXmp(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_KELON168
|
|
if (strcmp(protocol_name, "KELON168") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kKelon168Bits;
|
|
irsend.sendKelon168(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_TEKNOPOINT
|
|
if (strcmp(protocol_name, "TEKNOPOINT") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kTeknopointBits;
|
|
irsend.sendTeknopoint(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_HAIER_AC176
|
|
if (strcmp(protocol_name, "HAIER_AC176") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kHaierAC176Bits;
|
|
irsend.sendHaierAC176(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_BOSE
|
|
if (strcmp(protocol_name, "BOSE") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kBoseBits;
|
|
irsend.sendBose(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_SANYO_AC88
|
|
if (strcmp(protocol_name, "SANYO_AC88") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kSanyoAc88Bits;
|
|
irsend.sendSanyoAc88(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_TROTEC_3550
|
|
if (strcmp(protocol_name, "TROTEC_3550") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kTrotecBits;
|
|
irsend.sendTrotec3550(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_ARRIS
|
|
if (strcmp(protocol_name, "ARRIS") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kArrisBits;
|
|
irsend.sendArris(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_RHOSS
|
|
if (strcmp(protocol_name, "RHOSS") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kRhossBits;
|
|
irsend.sendRhoss(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_AIRTON
|
|
if (strcmp(protocol_name, "AIRTON") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kAirtonBits;
|
|
irsend.sendAirton(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_COOLIX48
|
|
if (strcmp(protocol_name, "COOLIX48") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kCoolix48Bits;
|
|
irsend.sendCoolix48(data, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_HITACHI_AC264
|
|
if (strcmp(protocol_name, "HITACHI_AC264") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kHitachiAc264Bits;
|
|
irsend.sendHitachiAc264(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
# ifdef IR_HITACHI_AC296
|
|
if (strcmp(protocol_name, "HITACHI_AC296") == 0) {
|
|
Log.notice(F("Sending IR signal with %s" CR), protocol_name);
|
|
if (valueBITS == 0)
|
|
valueBITS = kHitachiAc296Bits;
|
|
irsend.sendHitachiAc296(dataarray, valueBITS, valueRPT);
|
|
return true;
|
|
}
|
|
# endif
|
|
Log.warning(F("Unknown IR protocol" CR));
|
|
return false;
|
|
# endif
|
|
}
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayLORA.ino"
|
|
# 28 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayLORA.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZgatewayLORA
|
|
|
|
# include <LoRa.h>
|
|
# include <SPI.h>
|
|
# include <Wire.h>
|
|
|
|
void setupLORA() {
|
|
SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_SS);
|
|
LoRa.setPins(LORA_SS, LORA_RST, LORA_DI0);
|
|
|
|
if (!LoRa.begin(LORA_BAND)) {
|
|
Log.error(F("ZgatewayLORA setup failed!" CR));
|
|
while (1)
|
|
;
|
|
}
|
|
LoRa.receive();
|
|
Log.notice(F("LORA_SCK: %d" CR), LORA_SCK);
|
|
Log.notice(F("LORA_MISO: %d" CR), LORA_MISO);
|
|
Log.notice(F("LORA_MOSI: %d" CR), LORA_MOSI);
|
|
Log.notice(F("LORA_SS: %d" CR), LORA_SS);
|
|
Log.notice(F("LORA_RST: %d" CR), LORA_RST);
|
|
Log.notice(F("LORA_DI0: %d" CR), LORA_DI0);
|
|
LoRa.setTxPower(LORA_TX_POWER);
|
|
LoRa.setSpreadingFactor(LORA_SPREADING_FACTOR);
|
|
LoRa.setSignalBandwidth(LORA_SIGNAL_BANDWIDTH);
|
|
LoRa.setCodingRate4(LORA_CODING_RATE);
|
|
LoRa.setPreambleLength(LORA_PREAMBLE_LENGTH);
|
|
LoRa.setSyncWord(LORA_SYNC_WORD);
|
|
Log.trace(F("ZgatewayLORA setup done" CR));
|
|
}
|
|
|
|
void LORAtoMQTT() {
|
|
int packetSize = LoRa.parsePacket();
|
|
if (packetSize) {
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject LORAdata = jsonBuffer.to<JsonObject>();
|
|
Log.trace(F("Rcv. LORA" CR));
|
|
# ifdef ESP32
|
|
String taskMessage = "LORA Task running on core ";
|
|
taskMessage = taskMessage + xPortGetCoreID();
|
|
|
|
# endif
|
|
String packet;
|
|
packet = "";
|
|
for (int i = 0; i < packetSize; i++) {
|
|
packet += (char)LoRa.read();
|
|
}
|
|
LORAdata["rssi"] = (int)LoRa.packetRssi();
|
|
LORAdata["snr"] = (float)LoRa.packetSnr();
|
|
LORAdata["pferror"] = (float)LoRa.packetFrequencyError();
|
|
LORAdata["packetSize"] = (int)packetSize;
|
|
LORAdata["message"] = (char*)packet.c_str();
|
|
pub(subjectLORAtoMQTT, LORAdata);
|
|
if (repeatLORAwMQTT) {
|
|
Log.trace(F("Pub LORA for rpt" CR));
|
|
pub(subjectMQTTtoLORA, LORAdata);
|
|
}
|
|
}
|
|
}
|
|
|
|
# if jsonReceiving
|
|
void MQTTtoLORA(char* topicOri, JsonObject& LORAdata) {
|
|
if (cmpToMainTopic(topicOri, subjectMQTTtoLORA)) {
|
|
Log.trace(F("MQTTtoLORA json" CR));
|
|
const char* message = LORAdata["message"];
|
|
int txPower = LORAdata["txpower"] | LORA_TX_POWER;
|
|
int spreadingFactor = LORAdata["spreadingfactor"] | LORA_SPREADING_FACTOR;
|
|
long int frequency = LORAdata["frequency "] | LORA_BAND;
|
|
long int signalBandwidth = LORAdata["signalbandwidth"] | LORA_SIGNAL_BANDWIDTH;
|
|
int codingRateDenominator = LORAdata["codingrate"] | LORA_CODING_RATE;
|
|
int preambleLength = LORAdata["preamblelength"] | LORA_PREAMBLE_LENGTH;
|
|
byte syncWord = LORAdata["syncword"] | LORA_SYNC_WORD;
|
|
bool Crc = LORAdata["enablecrc"] | DEFAULT_CRC;
|
|
if (message) {
|
|
LoRa.setTxPower(txPower);
|
|
LoRa.setFrequency(frequency);
|
|
LoRa.setSpreadingFactor(spreadingFactor);
|
|
LoRa.setSignalBandwidth(signalBandwidth);
|
|
LoRa.setCodingRate4(codingRateDenominator);
|
|
LoRa.setPreambleLength(preambleLength);
|
|
LoRa.setSyncWord(syncWord);
|
|
if (Crc)
|
|
LoRa.enableCrc();
|
|
LoRa.beginPacket();
|
|
LoRa.print(message);
|
|
LoRa.endPacket();
|
|
Log.trace(F("MQTTtoLORA OK" CR));
|
|
pub(subjectGTWLORAtoMQTT, LORAdata);
|
|
} else {
|
|
Log.error(F("MQTTtoLORA Fail json" CR));
|
|
}
|
|
}
|
|
}
|
|
# endif
|
|
# if simpleReceiving
|
|
void MQTTtoLORA(char* topicOri, char* LORAdata) {
|
|
if (cmpToMainTopic(topicOri, subjectMQTTtoLORA)) {
|
|
LoRa.beginPacket();
|
|
LoRa.print(LORAdata);
|
|
LoRa.endPacket();
|
|
Log.notice(F("MQTTtoLORA OK" CR));
|
|
pub(subjectGTWLORAtoMQTT, LORAdata);
|
|
}
|
|
}
|
|
# endif
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayPilight.ino"
|
|
# 28 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayPilight.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZgatewayPilight
|
|
|
|
# ifdef ZradioCC1101
|
|
# include <ELECHOUSE_CC1101_SRC_DRV.h>
|
|
# endif
|
|
|
|
# include <ESPiLight.h>
|
|
ESPiLight rf(RF_EMITTER_GPIO);
|
|
|
|
void pilightCallback(const String& protocol, const String& message, int status,
|
|
size_t repeats, const String& deviceID) {
|
|
if (status == VALID) {
|
|
Log.trace(F("Creating RF PiLight buffer" CR));
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject RFPiLightdata = jsonBuffer.to<JsonObject>();
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer2;
|
|
JsonObject msg = jsonBuffer2.to<JsonObject>();
|
|
auto error = deserializeJson(jsonBuffer2, message);
|
|
if (error) {
|
|
Log.error(F("deserializeJson() failed: %s" CR), error.c_str());
|
|
return;
|
|
}
|
|
RFPiLightdata["message"] = msg;
|
|
RFPiLightdata["protocol"] = (const char*)protocol.c_str();
|
|
RFPiLightdata["length"] = (const char*)deviceID.c_str();
|
|
|
|
const char* device_id = deviceID.c_str();
|
|
if (!strlen(device_id)) {
|
|
|
|
|
|
char* choices[] = {"key", "unit", "device_id", "systemcode", "unitcode", "programcode"};
|
|
|
|
for (uint8_t i = 0; i < 6; i++) {
|
|
if (msg[choices[i]]) {
|
|
device_id = (const char*)msg[choices[i]];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
RFPiLightdata["value"] = device_id;
|
|
RFPiLightdata["repeats"] = (int)repeats;
|
|
RFPiLightdata["status"] = (int)status;
|
|
pub(subjectPilighttoMQTT, RFPiLightdata);
|
|
if (repeatPilightwMQTT) {
|
|
Log.trace(F("Pub Pilight for rpt" CR));
|
|
pub(subjectMQTTtoPilight, RFPiLightdata);
|
|
}
|
|
}
|
|
}
|
|
|
|
void setupPilight() {
|
|
# ifdef ZradioCC1101
|
|
ELECHOUSE_cc1101.Init();
|
|
ELECHOUSE_cc1101.setMHZ(CC1101_FREQUENCY);
|
|
ELECHOUSE_cc1101.SetRx(CC1101_FREQUENCY);
|
|
# endif
|
|
rf.setCallback(pilightCallback);
|
|
rf.initReceiver(RF_RECEIVER_GPIO);
|
|
pinMode(RF_EMITTER_GPIO, OUTPUT);
|
|
Log.notice(F("RF_EMITTER_GPIO: %d " CR), RF_EMITTER_GPIO);
|
|
Log.notice(F("RF_RECEIVER_GPIO: %d " CR), RF_RECEIVER_GPIO);
|
|
Log.trace(F("ZgatewayPilight command topic: %s%s%s" CR), mqtt_topic, gateway_name, subjectMQTTtoPilight);
|
|
Log.trace(F("ZgatewayPilight setup done " CR));
|
|
}
|
|
|
|
void savePilightConfig() {
|
|
Log.trace(F("saving Pilight config" CR));
|
|
DynamicJsonDocument json(4096);
|
|
deserializeJson(json, rf.enabledProtocols());
|
|
|
|
File configFile = SPIFFS.open("/pilight.json", "w");
|
|
if (!configFile) {
|
|
Log.error(F("failed to open config file for writing" CR));
|
|
}
|
|
|
|
serializeJsonPretty(json, Serial);
|
|
serializeJson(json, configFile);
|
|
configFile.close();
|
|
}
|
|
|
|
void loadPilightConfig() {
|
|
Log.trace(F("reading Pilight config file" CR));
|
|
File configFile = SPIFFS.open("/pilight.json", "r");
|
|
if (configFile) {
|
|
Log.trace(F("opened Pilight config file" CR));
|
|
DynamicJsonDocument json(configFile.size() * 4);
|
|
auto error = deserializeJson(json, configFile);
|
|
if (error) {
|
|
Log.error(F("deserialize config failed: %s, buffer capacity: %u" CR), error.c_str(), json.capacity());
|
|
}
|
|
serializeJson(json, Serial);
|
|
if (!json.isNull()) {
|
|
String rflimit;
|
|
serializeJson(json, rflimit);
|
|
rf.limitProtocols(rflimit);
|
|
} else {
|
|
Log.warning(F("failed to load json config" CR));
|
|
}
|
|
configFile.close();
|
|
}
|
|
}
|
|
|
|
void PilighttoMQTT() {
|
|
rf.loop();
|
|
}
|
|
|
|
void MQTTtoPilight(char* topicOri, JsonObject& Pilightdata) {
|
|
if (cmpToMainTopic(topicOri, subjectMQTTtoPilightProtocol)) {
|
|
bool success = false;
|
|
if (Pilightdata.containsKey("reset")) {
|
|
rf.limitProtocols(rf.availableProtocols());
|
|
savePilightConfig();
|
|
success = true;
|
|
}
|
|
if (Pilightdata.containsKey("limit")) {
|
|
String output;
|
|
serializeJson(Pilightdata["limit"], output);
|
|
rf.limitProtocols(output);
|
|
savePilightConfig();
|
|
success = true;
|
|
}
|
|
if (Pilightdata.containsKey("enabled")) {
|
|
Log.notice(F("PiLight protocols enabled: %s" CR), rf.enabledProtocols().c_str());
|
|
success = true;
|
|
}
|
|
if (Pilightdata.containsKey("available")) {
|
|
Log.notice(F("PiLight protocols available: %s" CR), rf.availableProtocols().c_str());
|
|
success = true;
|
|
}
|
|
|
|
if (success) {
|
|
pub(subjectGTWPilighttoMQTT, Pilightdata);
|
|
} else {
|
|
pub(subjectGTWPilighttoMQTT, "{\"Status\": \"Error\"}");
|
|
Log.error(F("MQTTtoPilightProtocol Fail json" CR));
|
|
}
|
|
} else if (cmpToMainTopic(topicOri, subjectMQTTtoPilight)) {
|
|
const char* message = Pilightdata["message"];
|
|
const char* protocol = Pilightdata["protocol"];
|
|
const char* raw = Pilightdata["raw"];
|
|
float tempMhz = Pilightdata["mhz"];
|
|
bool success = false;
|
|
if (raw) {
|
|
uint16_t codes[MAXPULSESTREAMLENGTH];
|
|
int repeats = rf.stringToRepeats(raw);
|
|
if (repeats < 0) {
|
|
switch (repeats) {
|
|
case ESPiLight::ERROR_INVALID_PULSETRAIN_MSG_R:
|
|
Log.trace(F("'r' not found in string, or has no data" CR));
|
|
break;
|
|
case ESPiLight::ERROR_INVALID_PULSETRAIN_MSG_END:
|
|
Log.trace(F("';' or '@' not found in data string" CR));
|
|
break;
|
|
}
|
|
repeats = 10;
|
|
}
|
|
int msgLength = rf.stringToPulseTrain(raw, codes, MAXPULSESTREAMLENGTH);
|
|
if (msgLength > 0) {
|
|
# ifdef ZradioCC1101
|
|
ELECHOUSE_cc1101.SetTx(CC1101_FREQUENCY);
|
|
rf.disableReceiver();
|
|
# endif
|
|
rf.sendPulseTrain(codes, msgLength, repeats);
|
|
Log.notice(F("MQTTtoPilight raw ok" CR));
|
|
success = true;
|
|
} else {
|
|
Log.trace(F("MQTTtoPilight raw KO" CR));
|
|
switch (msgLength) {
|
|
case ESPiLight::ERROR_INVALID_PULSETRAIN_MSG_C:
|
|
Log.trace(F("'c' not found in string, or has no data" CR));
|
|
break;
|
|
case ESPiLight::ERROR_INVALID_PULSETRAIN_MSG_P:
|
|
Log.trace(F("'p' not found in string, or has no data" CR));
|
|
break;
|
|
case ESPiLight::ERROR_INVALID_PULSETRAIN_MSG_END:
|
|
Log.trace(F("';' or '@' not found in data string" CR));
|
|
break;
|
|
case ESPiLight::ERROR_INVALID_PULSETRAIN_MSG_TYPE:
|
|
Log.trace(F("pulse type not defined" CR));
|
|
break;
|
|
}
|
|
Log.error(F("Invalid JSON: raw data malformed" CR));
|
|
}
|
|
}
|
|
if (message && protocol) {
|
|
Log.trace(F("MQTTtoPilight msg & protocol ok" CR));
|
|
# ifdef ZradioCC1101
|
|
ELECHOUSE_cc1101.SetTx(CC1101_FREQUENCY);
|
|
rf.disableReceiver();
|
|
# endif
|
|
int msgLength = rf.send(protocol, message);
|
|
if (msgLength > 0) {
|
|
Log.trace(F("Adv data MQTTtoPilight push state via PilighttoMQTT" CR));
|
|
pub(subjectGTWPilighttoMQTT, Pilightdata);
|
|
success = true;
|
|
} else {
|
|
switch (msgLength) {
|
|
case ESPiLight::ERROR_UNAVAILABLE_PROTOCOL:
|
|
Log.error(F("protocol is not available" CR));
|
|
break;
|
|
case ESPiLight::ERROR_INVALID_PILIGHT_MSG:
|
|
Log.error(F("message is invalid" CR));
|
|
break;
|
|
case ESPiLight::ERROR_INVALID_JSON:
|
|
Log.error(F("message is not a proper json object" CR));
|
|
break;
|
|
case ESPiLight::ERROR_NO_OUTPUT_PIN:
|
|
Log.error(F("no transmitter pin" CR));
|
|
break;
|
|
default:
|
|
Log.error(F("Invalid JSON: can't read message/protocol" CR));
|
|
}
|
|
}
|
|
}
|
|
if (Pilightdata.containsKey("active")) {
|
|
Log.trace(F("PiLight active:" CR));
|
|
activeReceiver = ACTIVE_PILIGHT;
|
|
success = true;
|
|
}
|
|
# ifdef ZradioCC1101
|
|
if (Pilightdata.containsKey("mhz") && validFrequency(tempMhz)) {
|
|
receiveMhz = tempMhz;
|
|
Log.notice(F("PiLight Receive mhz: %F" CR), receiveMhz);
|
|
success = true;
|
|
}
|
|
# endif
|
|
if (success) {
|
|
pub(subjectGTWPilighttoMQTT, Pilightdata);
|
|
} else {
|
|
pub(subjectGTWPilighttoMQTT, "{\"Status\": \"Error\"}");
|
|
Log.error(F("MQTTtoPilight Fail json" CR));
|
|
}
|
|
enableActiveReceiver(false);
|
|
}
|
|
}
|
|
|
|
extern void disablePilightReceive() {
|
|
Log.trace(F("disablePilightReceive" CR));
|
|
rf.initReceiver(-1);
|
|
rf.disableReceiver();
|
|
};
|
|
|
|
extern void enablePilightReceive() {
|
|
# ifdef ZradioCC1101
|
|
Log.notice(F("Switching to Pilight Receiver: %F" CR), receiveMhz);
|
|
# else
|
|
Log.notice(F("Switching to Pilight Receiver" CR));
|
|
# endif
|
|
# ifdef ZgatewayRF
|
|
disableRFReceive();
|
|
# endif
|
|
# ifdef ZgatewayRF2
|
|
disableRF2Receive();
|
|
# endif
|
|
# ifdef ZgatewayRTL_433
|
|
disableRTLreceive();
|
|
# endif
|
|
|
|
# ifdef ZradioCC1101
|
|
ELECHOUSE_cc1101.SetRx(receiveMhz);
|
|
# endif
|
|
rf.setCallback(pilightCallback);
|
|
rf.initReceiver(RF_RECEIVER_GPIO);
|
|
pinMode(RF_EMITTER_GPIO, OUTPUT);
|
|
rf.enableReceiver();
|
|
loadPilightConfig();
|
|
};
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayRF.ino"
|
|
# 28 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayRF.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZgatewayRF
|
|
|
|
# ifdef ZradioCC1101
|
|
# include <ELECHOUSE_CC1101_SRC_DRV.h>
|
|
# endif
|
|
|
|
# include <RCSwitch.h>
|
|
|
|
RCSwitch mySwitch = RCSwitch();
|
|
|
|
|
|
static const char* bin2tristate(const char* bin) {
|
|
static char returnValue[50];
|
|
int pos = 0;
|
|
int pos2 = 0;
|
|
while (bin[pos] != '\0' && bin[pos + 1] != '\0') {
|
|
if (bin[pos] == '0' && bin[pos + 1] == '0') {
|
|
returnValue[pos2] = '0';
|
|
} else if (bin[pos] == '1' && bin[pos + 1] == '1') {
|
|
returnValue[pos2] = '1';
|
|
} else if (bin[pos] == '0' && bin[pos + 1] == '1') {
|
|
returnValue[pos2] = 'F';
|
|
} else {
|
|
return "-";
|
|
}
|
|
pos = pos + 2;
|
|
pos2++;
|
|
}
|
|
returnValue[pos2] = '\0';
|
|
return returnValue;
|
|
}
|
|
|
|
static char* dec2binWzerofill(unsigned long Dec, unsigned int bitLength) {
|
|
static char bin[64];
|
|
unsigned int i = 0;
|
|
|
|
while (Dec > 0) {
|
|
bin[32 + i++] = ((Dec & 1) > 0) ? '1' : '0';
|
|
Dec = Dec >> 1;
|
|
}
|
|
|
|
for (unsigned int j = 0; j < bitLength; j++) {
|
|
if (j >= bitLength - i) {
|
|
bin[j] = bin[31 + i - (j - (bitLength - i))];
|
|
} else {
|
|
bin[j] = '0';
|
|
}
|
|
}
|
|
bin[bitLength] = '\0';
|
|
|
|
return bin;
|
|
}
|
|
|
|
# if defined(ZmqttDiscovery) && !defined(RF_DISABLE_TRANSMIT) && defined(RFmqttDiscovery)
|
|
|
|
void RFtoMQTTdiscovery(SIGNAL_SIZE_UL_ULL MQTTvalue) {
|
|
|
|
char val[11];
|
|
sprintf(val, "%lu", MQTTvalue);
|
|
Log.trace(F("RF Entity Discovered, create HA Discovery CFG" CR));
|
|
char* switchRF[2] = {val, "RF"};
|
|
Log.trace(F("CreateDiscoverySwitch: %s" CR), switchRF[1]);
|
|
# if valueAsATopic
|
|
String discovery_topic = String(subjectRFtoMQTT) + "/" + String(switchRF[0]);
|
|
# else
|
|
String discovery_topic = String(subjectRFtoMQTT);
|
|
# endif
|
|
|
|
String theUniqueId = getUniqueId("-" + String(switchRF[0]), "-" + String(switchRF[1]));
|
|
|
|
announceDeviceTrigger(
|
|
false,
|
|
(char*)discovery_topic.c_str(),
|
|
"", "",
|
|
(char*)theUniqueId.c_str(),
|
|
"", "", "", "");
|
|
}
|
|
# endif
|
|
|
|
void setupRF() {
|
|
|
|
Log.notice(F("RF_EMITTER_GPIO: %d " CR), RF_EMITTER_GPIO);
|
|
Log.notice(F("RF_RECEIVER_GPIO: %d " CR), RF_RECEIVER_GPIO);
|
|
# ifdef ZradioCC1101
|
|
ELECHOUSE_cc1101.Init();
|
|
ELECHOUSE_cc1101.SetRx(receiveMhz);
|
|
# endif
|
|
# ifdef RF_DISABLE_TRANSMIT
|
|
mySwitch.disableTransmit();
|
|
# else
|
|
mySwitch.enableTransmit(RF_EMITTER_GPIO);
|
|
# endif
|
|
mySwitch.setRepeatTransmit(RF_EMITTER_REPEAT);
|
|
mySwitch.enableReceive(RF_RECEIVER_GPIO);
|
|
Log.trace(F("ZgatewayRF command topic: %s%s%s" CR), mqtt_topic, gateway_name, subjectMQTTtoRF);
|
|
Log.trace(F("ZgatewayRF setup done" CR));
|
|
}
|
|
|
|
void RFtoMQTT() {
|
|
if (mySwitch.available()) {
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject RFdata = jsonBuffer.to<JsonObject>();
|
|
Log.trace(F("Rcv. RF" CR));
|
|
# ifdef ESP32
|
|
Log.trace(F("RF Task running on core :%d" CR), xPortGetCoreID());
|
|
# endif
|
|
SIGNAL_SIZE_UL_ULL MQTTvalue = mySwitch.getReceivedValue();
|
|
int length = mySwitch.getReceivedBitlength();
|
|
const char* binary = dec2binWzerofill(MQTTvalue, length);
|
|
|
|
RFdata["value"] = (SIGNAL_SIZE_UL_ULL)MQTTvalue;
|
|
RFdata["protocol"] = (int)mySwitch.getReceivedProtocol();
|
|
RFdata["length"] = (int)mySwitch.getReceivedBitlength();
|
|
RFdata["delay"] = (int)mySwitch.getReceivedDelay();
|
|
RFdata["tre_state"] = bin2tristate(binary);
|
|
RFdata["binary"] = binary;
|
|
|
|
unsigned int* raw = mySwitch.getReceivedRawdata();
|
|
String rawDump = "";
|
|
for (unsigned int i = 0; i <= length * 2; i++) {
|
|
rawDump = rawDump + String(raw[i]) + ",";
|
|
}
|
|
RFdata["raw"] = rawDump.c_str();
|
|
|
|
# ifdef ZradioCC1101
|
|
RFdata["mhz"] = receiveMhz;
|
|
# endif
|
|
mySwitch.resetAvailable();
|
|
|
|
if (!isAduplicateSignal(MQTTvalue) && MQTTvalue != 0) {
|
|
# if defined(ZmqttDiscovery) && !defined(RF_DISABLE_TRANSMIT) && defined(RFmqttDiscovery)
|
|
if (disc)
|
|
RFtoMQTTdiscovery(MQTTvalue);
|
|
# endif
|
|
pub(subjectRFtoMQTT, RFdata);
|
|
|
|
Log.trace(F("Store val: %u" CR), (unsigned long)MQTTvalue);
|
|
storeSignalValue(MQTTvalue);
|
|
if (repeatRFwMQTT) {
|
|
Log.trace(F("Pub RF for rpt" CR));
|
|
pub(subjectMQTTtoRF, RFdata);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# if simpleReceiving
|
|
void MQTTtoRF(char* topicOri, char* datacallback) {
|
|
# ifdef ZradioCC1101
|
|
ELECHOUSE_cc1101.SetTx(receiveMhz);
|
|
# endif
|
|
mySwitch.disableReceive();
|
|
mySwitch.enableTransmit(RF_EMITTER_GPIO);
|
|
SIGNAL_SIZE_UL_ULL data = STRTO_UL_ULL(datacallback, NULL, 10);
|
|
|
|
|
|
|
|
String topic = topicOri;
|
|
int valuePRT = 0;
|
|
int valuePLSL = 0;
|
|
int valueBITS = 0;
|
|
int pos = topic.lastIndexOf(RFprotocolKey);
|
|
if (pos != -1) {
|
|
pos = pos + +strlen(RFprotocolKey);
|
|
valuePRT = (topic.substring(pos, pos + 1)).toInt();
|
|
}
|
|
|
|
int pos2 = topic.lastIndexOf(RFpulselengthKey);
|
|
if (pos2 != -1) {
|
|
pos2 = pos2 + strlen(RFpulselengthKey);
|
|
valuePLSL = (topic.substring(pos2, pos2 + 3)).toInt();
|
|
}
|
|
int pos3 = topic.lastIndexOf(RFbitsKey);
|
|
if (pos3 != -1) {
|
|
pos3 = pos3 + strlen(RFbitsKey);
|
|
valueBITS = (topic.substring(pos3, pos3 + 2)).toInt();
|
|
}
|
|
|
|
if ((cmpToMainTopic(topicOri, subjectMQTTtoRF)) && (valuePRT == 0) && (valuePLSL == 0) && (valueBITS == 0)) {
|
|
Log.trace(F("MQTTtoRF dflt" CR));
|
|
mySwitch.setProtocol(1, 350);
|
|
mySwitch.send(data, 24);
|
|
|
|
pub(subjectGTWRFtoMQTT, datacallback);
|
|
} else if ((valuePRT != 0) || (valuePLSL != 0) || (valueBITS != 0)) {
|
|
Log.trace(F("MQTTtoRF usr par." CR));
|
|
if (valuePRT == 0)
|
|
valuePRT = 1;
|
|
if (valuePLSL == 0)
|
|
valuePLSL = 350;
|
|
if (valueBITS == 0)
|
|
valueBITS = 24;
|
|
Log.notice(F("RF Protocol:%d" CR), valuePRT);
|
|
Log.notice(F("RF Pulse Lgth: %d" CR), valuePLSL);
|
|
Log.notice(F("Bits nb: %d" CR), valueBITS);
|
|
mySwitch.setProtocol(valuePRT, valuePLSL);
|
|
mySwitch.send(data, valueBITS);
|
|
|
|
pub(subjectGTWRFtoMQTT, datacallback);
|
|
}
|
|
# ifdef ZradioCC1101
|
|
ELECHOUSE_cc1101.SetRx(receiveMhz);
|
|
mySwitch.disableTransmit();
|
|
mySwitch.enableReceive(RF_RECEIVER_GPIO);
|
|
# endif
|
|
}
|
|
# endif
|
|
|
|
# if jsonReceiving
|
|
void MQTTtoRF(char* topicOri, JsonObject& RFdata) {
|
|
if (cmpToMainTopic(topicOri, subjectMQTTtoRF)) {
|
|
Log.trace(F("MQTTtoRF json" CR));
|
|
SIGNAL_SIZE_UL_ULL data = RFdata["value"];
|
|
if (data != 0) {
|
|
int valuePRT = RFdata["protocol"] | 1;
|
|
int valuePLSL = RFdata["delay"] | 350;
|
|
int valueBITS = RFdata["length"] | 24;
|
|
int valueRPT = RFdata["repeat"] | RF_EMITTER_REPEAT;
|
|
Log.notice(F("RF Protocol:%d" CR), valuePRT);
|
|
Log.notice(F("RF Pulse Lgth: %d" CR), valuePLSL);
|
|
Log.notice(F("Bits nb: %d" CR), valueBITS);
|
|
# ifdef ZradioCC1101
|
|
float trMhz = RFdata["mhz"] | CC1101_FREQUENCY;
|
|
if (validFrequency((int)trMhz)) {
|
|
ELECHOUSE_cc1101.SetTx(trMhz);
|
|
Log.notice(F("Transmit mhz: %F" CR), trMhz);
|
|
}
|
|
# endif
|
|
mySwitch.disableReceive();
|
|
mySwitch.enableTransmit(RF_EMITTER_GPIO);
|
|
mySwitch.setRepeatTransmit(valueRPT);
|
|
mySwitch.setProtocol(valuePRT, valuePLSL);
|
|
mySwitch.send(data, valueBITS);
|
|
Log.notice(F("MQTTtoRF OK" CR));
|
|
pub(subjectGTWRFtoMQTT, RFdata);
|
|
mySwitch.setRepeatTransmit(RF_EMITTER_REPEAT);
|
|
} else {
|
|
bool success = false;
|
|
if (RFdata.containsKey("active")) {
|
|
Log.trace(F("RF active:" CR));
|
|
activeReceiver = ACTIVE_RF;
|
|
success = true;
|
|
}
|
|
# ifdef ZradioCC1101
|
|
float tempMhz = RFdata["mhz"];
|
|
if (RFdata.containsKey("mhz") && validFrequency(tempMhz)) {
|
|
receiveMhz = tempMhz;
|
|
Log.notice(F("Receive mhz: %F" CR), receiveMhz);
|
|
success = true;
|
|
}
|
|
# endif
|
|
if (success) {
|
|
pub(subjectGTWRFtoMQTT, RFdata);
|
|
} else {
|
|
# ifndef ARDUINO_AVR_UNO
|
|
pub(subjectGTWRFtoMQTT, "{\"Status\": \"Error\"}");
|
|
# endif
|
|
Log.error(F("MQTTtoRF Fail json" CR));
|
|
}
|
|
}
|
|
enableActiveReceiver(false);
|
|
}
|
|
}
|
|
# endif
|
|
|
|
int receiveInterupt = -1;
|
|
|
|
void disableRFReceive() {
|
|
Log.trace(F("disableRFReceive %d" CR), receiveInterupt);
|
|
if (receiveInterupt != -1) {
|
|
receiveInterupt = -1;
|
|
mySwitch.disableReceive();
|
|
}
|
|
}
|
|
|
|
void enableRFReceive() {
|
|
# ifdef ZradioCC1101
|
|
Log.notice(F("Switching to RF Receiver: %F" CR), receiveMhz);
|
|
# else
|
|
Log.notice(F("Switching to RF Receiver" CR));
|
|
# endif
|
|
# ifndef ARDUINO_AVR_UNO
|
|
# ifdef ZgatewayPilight
|
|
disablePilightReceive();
|
|
# endif
|
|
# ifdef ZgatewayRTL_433
|
|
disableRTLreceive();
|
|
# endif
|
|
# endif
|
|
# ifdef ZgatewayRF2
|
|
disableRF2Receive();
|
|
# endif
|
|
|
|
# ifdef ZradioCC1101
|
|
ELECHOUSE_cc1101.SetRx(receiveMhz);
|
|
# endif
|
|
mySwitch.disableTransmit();
|
|
receiveInterupt = RF_RECEIVER_GPIO;
|
|
mySwitch.enableReceive(RF_RECEIVER_GPIO);
|
|
}
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayRF2.ino"
|
|
# 36 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayRF2.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZgatewayRF2
|
|
|
|
# ifdef ZradioCC1101
|
|
# include <ELECHOUSE_CC1101_SRC_DRV.h>
|
|
# endif
|
|
|
|
# include <NewRemoteReceiver.h>
|
|
# include <NewRemoteTransmitter.h>
|
|
|
|
struct RF2rxd {
|
|
unsigned int period;
|
|
unsigned long address;
|
|
unsigned long groupBit;
|
|
unsigned long unit;
|
|
unsigned long switchType;
|
|
bool hasNewData;
|
|
};
|
|
|
|
RF2rxd rf2rd;
|
|
|
|
void setupRF2() {
|
|
# ifdef ZradioCC1101
|
|
ELECHOUSE_cc1101.Init();
|
|
ELECHOUSE_cc1101.setMHZ(receiveMhz);
|
|
ELECHOUSE_cc1101.SetRx(receiveMhz);
|
|
# endif
|
|
NewRemoteReceiver::init(RF_RECEIVER_GPIO, 2, rf2Callback);
|
|
Log.notice(F("RF_EMITTER_GPIO: %d " CR), RF_EMITTER_GPIO);
|
|
Log.notice(F("RF_RECEIVER_GPIO: %d " CR), RF_RECEIVER_GPIO);
|
|
Log.trace(F("ZgatewayRF2 command topic: %s%s%s" CR), mqtt_topic, gateway_name, subjectMQTTtoRF2);
|
|
Log.trace(F("ZgatewayRF2 setup done " CR));
|
|
pinMode(RF_EMITTER_GPIO, OUTPUT);
|
|
digitalWrite(RF_EMITTER_GPIO, LOW);
|
|
}
|
|
|
|
# ifdef ZmqttDiscovery
|
|
|
|
void RF2toMQTTdiscovery(JsonObject& data) {
|
|
Log.trace(F("switchRF2Discovery" CR));
|
|
String payloadonstr;
|
|
String payloadoffstr;
|
|
|
|
int org_switchtype = data["switchType"];
|
|
data["switchType"] = 1;
|
|
serializeJson(data, payloadonstr);
|
|
data["switchType"] = 0;
|
|
serializeJson(data, payloadoffstr);
|
|
data["switchType"] = org_switchtype;
|
|
|
|
String switchname;
|
|
switchname = "RF2_" + String((int)data["unit"]) + "_" +
|
|
String((int)data["groupbit"]) + "_" +
|
|
String((unsigned long)data["address"]);
|
|
|
|
char* switchRF[8] = {"switch",
|
|
(char*)switchname.c_str(),
|
|
"",
|
|
"",
|
|
"",
|
|
(char*)payloadonstr.c_str(),
|
|
(char*)payloadoffstr.c_str(),
|
|
""};
|
|
|
|
|
|
|
|
Log.trace(F("CreateDiscoverySwitch: %s" CR), switchRF[1]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
createDiscovery(switchRF[0], "", switchRF[1],
|
|
(char*)getUniqueId(switchRF[1], "").c_str(), will_Topic,
|
|
switchRF[3], switchRF[4], switchRF[5], switchRF[6],
|
|
switchRF[7], 0, "", "", true, subjectMQTTtoRF2,
|
|
"", "", "", "", false,
|
|
stateClassNone);
|
|
}
|
|
# endif
|
|
|
|
void RF2toMQTT() {
|
|
if (rf2rd.hasNewData) {
|
|
Log.trace(F("Creating RF2 buffer" CR));
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject RF2data = jsonBuffer.to<JsonObject>();
|
|
|
|
rf2rd.hasNewData = false;
|
|
|
|
Log.trace(F("Rcv. RF2" CR));
|
|
RF2data["unit"] = (int)rf2rd.unit;
|
|
RF2data["groupBit"] = (int)rf2rd.groupBit;
|
|
RF2data["period"] = (int)rf2rd.period;
|
|
RF2data["address"] = (unsigned long)rf2rd.address;
|
|
RF2data["switchType"] = (int)rf2rd.switchType;
|
|
# ifdef ZmqttDiscovery
|
|
if (disc)
|
|
RF2toMQTTdiscovery(RF2data);
|
|
# endif
|
|
|
|
pub(subjectRF2toMQTT, RF2data);
|
|
}
|
|
}
|
|
|
|
void rf2Callback(unsigned int period, unsigned long address, unsigned long groupBit, unsigned long unit, unsigned long switchType) {
|
|
rf2rd.period = period;
|
|
rf2rd.address = address;
|
|
rf2rd.groupBit = groupBit;
|
|
rf2rd.unit = unit;
|
|
rf2rd.switchType = switchType;
|
|
rf2rd.hasNewData = true;
|
|
}
|
|
|
|
# if simpleReceiving
|
|
void MQTTtoRF2(char* topicOri, char* datacallback) {
|
|
# ifdef ZradioCC1101
|
|
NewRemoteReceiver::disable();
|
|
ELECHOUSE_cc1101.SetTx(CC1101_FREQUENCY);
|
|
# endif
|
|
|
|
|
|
|
|
String topic = topicOri;
|
|
bool boolSWITCHTYPE;
|
|
boolSWITCHTYPE = to_bool(datacallback);
|
|
bool isDimCommand = false;
|
|
|
|
long valueCODE = 0;
|
|
int valueUNIT = -1;
|
|
int valuePERIOD = 0;
|
|
int valueGROUP = 0;
|
|
int valueDIM = -1;
|
|
|
|
int pos = topic.lastIndexOf(RF2codeKey);
|
|
if (pos != -1) {
|
|
pos = pos + +strlen(RF2codeKey);
|
|
valueCODE = (topic.substring(pos, pos + 8)).toInt();
|
|
Log.notice(F("RF2 code: %l" CR), valueCODE);
|
|
}
|
|
int pos2 = topic.lastIndexOf(RF2periodKey);
|
|
if (pos2 != -1) {
|
|
pos2 = pos2 + strlen(RF2periodKey);
|
|
valuePERIOD = (topic.substring(pos2, pos2 + 3)).toInt();
|
|
Log.notice(F("RF2 Period: %d" CR), valuePERIOD);
|
|
}
|
|
int pos3 = topic.lastIndexOf(RF2unitKey);
|
|
if (pos3 != -1) {
|
|
pos3 = pos3 + strlen(RF2unitKey);
|
|
valueUNIT = (topic.substring(pos3, topic.indexOf("/", pos3))).toInt();
|
|
Log.notice(F("Unit: %d" CR), valueUNIT);
|
|
}
|
|
int pos4 = topic.lastIndexOf(RF2groupKey);
|
|
if (pos4 != -1) {
|
|
pos4 = pos4 + strlen(RF2groupKey);
|
|
valueGROUP = (topic.substring(pos4, pos4 + 1)).toInt();
|
|
Log.notice(F("RF2 Group: %d" CR), valueGROUP);
|
|
}
|
|
int pos5 = topic.lastIndexOf(RF2dimKey);
|
|
if (pos5 != -1) {
|
|
isDimCommand = true;
|
|
valueDIM = atoi(datacallback);
|
|
Log.notice(F("RF2 Dim: %d" CR), valueDIM);
|
|
}
|
|
|
|
if ((topic == subjectMQTTtoRF2) || (valueCODE != 0) || (valueUNIT != -1) || (valuePERIOD != 0)) {
|
|
Log.trace(F("MQTTtoRF2" CR));
|
|
if (valueCODE == 0)
|
|
valueCODE = 8233378;
|
|
if (valueUNIT == -1)
|
|
valueUNIT = 0;
|
|
if (valuePERIOD == 0)
|
|
valuePERIOD = 272;
|
|
NewRemoteReceiver::disable();
|
|
Log.trace(F("Creating transmitter" CR));
|
|
NewRemoteTransmitter transmitter(valueCODE, RF_EMITTER_GPIO, valuePERIOD, RF2_EMITTER_REPEAT);
|
|
Log.trace(F("Sending data" CR));
|
|
if (valueGROUP) {
|
|
if (isDimCommand) {
|
|
transmitter.sendGroupDim(valueDIM);
|
|
} else {
|
|
transmitter.sendGroup(boolSWITCHTYPE);
|
|
}
|
|
} else {
|
|
if (isDimCommand) {
|
|
transmitter.sendDim(valueUNIT, valueDIM);
|
|
} else {
|
|
transmitter.sendUnit(valueUNIT, boolSWITCHTYPE);
|
|
}
|
|
}
|
|
Log.trace(F("Data sent" CR));
|
|
NewRemoteReceiver::enable();
|
|
|
|
|
|
String MQTTAddress;
|
|
String MQTTperiod;
|
|
String MQTTunit;
|
|
String MQTTgroupBit;
|
|
String MQTTswitchType;
|
|
String MQTTdimLevel;
|
|
|
|
MQTTAddress = String(valueCODE);
|
|
MQTTperiod = String(valuePERIOD);
|
|
MQTTunit = String(valueUNIT);
|
|
MQTTgroupBit = String(rf2rd.groupBit);
|
|
MQTTswitchType = String(boolSWITCHTYPE);
|
|
MQTTdimLevel = String(valueDIM);
|
|
String MQTTRF2string;
|
|
Log.trace(F("Adv data MQTTtoRF2 push state via RF2toMQTT" CR));
|
|
if (isDimCommand) {
|
|
MQTTRF2string = subjectRF2toMQTT + String("/") + RF2codeKey + MQTTAddress + String("/") + RF2unitKey + MQTTunit + String("/") + RF2groupKey + MQTTgroupBit + String("/") + RF2dimKey + String("/") + RF2periodKey + MQTTperiod;
|
|
pub((char*)MQTTRF2string.c_str(), (char*)MQTTdimLevel.c_str());
|
|
} else {
|
|
MQTTRF2string = subjectRF2toMQTT + String("/") + RF2codeKey + MQTTAddress + String("/") + RF2unitKey + MQTTunit + String("/") + RF2groupKey + MQTTgroupBit + String("/") + RF2periodKey + MQTTperiod;
|
|
pub((char*)MQTTRF2string.c_str(), (char*)MQTTswitchType.c_str());
|
|
}
|
|
}
|
|
# ifdef ZradioCC1101
|
|
ELECHOUSE_cc1101.SetRx(receiveMhz);
|
|
NewRemoteReceiver::enable();
|
|
# endif
|
|
}
|
|
# endif
|
|
|
|
# if jsonReceiving
|
|
void MQTTtoRF2(char* topicOri, JsonObject& RF2data) {
|
|
|
|
if (cmpToMainTopic(topicOri, subjectMQTTtoRF2)) {
|
|
Log.trace(F("MQTTtoRF2 json" CR));
|
|
int boolSWITCHTYPE = RF2data["switchType"] | 99;
|
|
bool success = false;
|
|
if (boolSWITCHTYPE != 99) {
|
|
# ifdef ZradioCC1101
|
|
NewRemoteReceiver::disable();
|
|
ELECHOUSE_cc1101.SetTx(CC1101_FREQUENCY);
|
|
# endif
|
|
Log.trace(F("MQTTtoRF2 switch type ok" CR));
|
|
bool isDimCommand = boolSWITCHTYPE == 2;
|
|
unsigned long valueCODE = RF2data["address"];
|
|
int valueUNIT = RF2data["unit"] | -1;
|
|
int valuePERIOD = RF2data["period"];
|
|
int valueGROUP = RF2data["group"];
|
|
int valueDIM = RF2data["dim"] | -1;
|
|
if ((valueCODE != 0) || (valueUNIT != -1) || (valuePERIOD != 0)) {
|
|
Log.trace(F("MQTTtoRF2" CR));
|
|
if (valueCODE == 0)
|
|
valueCODE = 8233378;
|
|
if (valueUNIT == -1)
|
|
valueUNIT = 0;
|
|
if (valuePERIOD == 0)
|
|
valuePERIOD = 272;
|
|
NewRemoteReceiver::disable();
|
|
NewRemoteTransmitter transmitter(valueCODE, RF_EMITTER_GPIO, valuePERIOD, RF2_EMITTER_REPEAT);
|
|
Log.trace(F("Sending" CR));
|
|
if (valueGROUP) {
|
|
if (isDimCommand) {
|
|
transmitter.sendGroupDim(valueDIM);
|
|
} else {
|
|
transmitter.sendGroup(boolSWITCHTYPE);
|
|
}
|
|
} else {
|
|
if (isDimCommand) {
|
|
transmitter.sendDim(valueUNIT, valueDIM);
|
|
} else {
|
|
transmitter.sendUnit(valueUNIT, boolSWITCHTYPE);
|
|
}
|
|
}
|
|
Log.notice(F("MQTTtoRF2 OK" CR));
|
|
NewRemoteReceiver::enable();
|
|
|
|
success = true;
|
|
}
|
|
}
|
|
if (RF2data.containsKey("active")) {
|
|
Log.trace(F("RF2 active:" CR));
|
|
activeReceiver = ACTIVE_RF2;
|
|
success = true;
|
|
}
|
|
# ifdef ZradioCC1101
|
|
float tempMhz = RF2data["mhz"];
|
|
if (RF2data.containsKey("mhz") && validFrequency(tempMhz)) {
|
|
receiveMhz = tempMhz;
|
|
Log.notice(F("Receive mhz: %F" CR), receiveMhz);
|
|
success = true;
|
|
}
|
|
# endif
|
|
if (success) {
|
|
pub(subjectGTWRF2toMQTT, RF2data);
|
|
} else {
|
|
# ifndef ARDUINO_AVR_UNO
|
|
pub(subjectGTWRF2toMQTT, "{\"Status\": \"Error\"}");
|
|
# endif
|
|
Log.error(F("MQTTtoRF2 failed json read" CR));
|
|
}
|
|
enableActiveReceiver(false);
|
|
}
|
|
}
|
|
# endif
|
|
|
|
void disableRF2Receive() {
|
|
Log.trace(F("disableRF2Receive" CR));
|
|
NewRemoteReceiver::deinit();
|
|
NewRemoteReceiver::init(-1, 2, rf2Callback);
|
|
NewRemoteReceiver::deinit();
|
|
}
|
|
|
|
void enableRF2Receive() {
|
|
# ifdef ZradioCC1101
|
|
Log.notice(F("Switching to RF2 Receiver: %F" CR), receiveMhz);
|
|
# else
|
|
Log.notice(F("Switching to RF2 Receiver" CR));
|
|
# endif
|
|
# ifdef ZgatewayPilight
|
|
disablePilightReceive();
|
|
# endif
|
|
# ifdef ZgatewayRTL_433
|
|
disableRTLreceive();
|
|
# endif
|
|
# ifdef ZgatewayRF
|
|
disableRFReceive();
|
|
# endif
|
|
|
|
NewRemoteReceiver::init(RF_RECEIVER_GPIO, 2, rf2Callback);
|
|
# ifdef ZradioCC1101
|
|
ELECHOUSE_cc1101.SetRx(receiveMhz);
|
|
# endif
|
|
}
|
|
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayRFM69.ino"
|
|
# 31 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayRFM69.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZgatewayRFM69
|
|
|
|
# include <EEPROM.h>
|
|
# include <RFM69.h>
|
|
|
|
char RadioConfig[128];
|
|
|
|
|
|
|
|
struct _GLOBAL_CONFIG {
|
|
uint32_t checksum;
|
|
char rfmapname[32];
|
|
char encryptkey[16 + 1];
|
|
uint8_t networkid;
|
|
uint8_t nodeid;
|
|
uint8_t powerlevel;
|
|
uint8_t rfmfrequency;
|
|
};
|
|
|
|
#define GC_POWER_LEVEL (pGC->powerlevel & 0x1F)
|
|
#define GC_IS_RFM69HCW ((pGC->powerlevel & 0x80) != 0)
|
|
#define SELECTED_FREQ(f) ((pGC->rfmfrequency == f) ? "selected" : "")
|
|
|
|
struct _GLOBAL_CONFIG* pGC;
|
|
|
|
|
|
uint32_t gc_checksum() {
|
|
uint8_t* p = (uint8_t*)pGC;
|
|
uint32_t checksum = 0;
|
|
p += sizeof(pGC->checksum);
|
|
for (size_t i = 0; i < (sizeof(*pGC) - 4); i++) {
|
|
checksum += *p++;
|
|
}
|
|
return checksum;
|
|
}
|
|
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
void eeprom_setup() {
|
|
EEPROM.begin(4096);
|
|
pGC = (struct _GLOBAL_CONFIG*)EEPROM.getDataPtr();
|
|
|
|
if (gc_checksum() != pGC->checksum) {
|
|
Log.trace(F("Factory reset" CR));
|
|
memset(pGC, 0, sizeof(*pGC));
|
|
strcpy_P(pGC->encryptkey, ENCRYPTKEY);
|
|
strcpy_P(pGC->rfmapname, RFM69AP_NAME);
|
|
pGC->networkid = NETWORKID;
|
|
pGC->nodeid = NODEID;
|
|
pGC->powerlevel = ((IS_RFM69HCW) ? 0x80 : 0x00) | POWER_LEVEL;
|
|
pGC->rfmfrequency = FREQUENCY;
|
|
pGC->checksum = gc_checksum();
|
|
EEPROM.commit();
|
|
}
|
|
}
|
|
# endif
|
|
|
|
RFM69 radio;
|
|
|
|
void setupRFM69(void) {
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
eeprom_setup();
|
|
# endif
|
|
int freq;
|
|
static const char PROGMEM JSONtemplate[] =
|
|
R"({"msgType":"config","freq":%d,"rfm69hcw":%d,"netid":%d,"power":%d})";
|
|
char payload[128];
|
|
|
|
radio = RFM69(RFM69_CS, RFM69_IRQ, GC_IS_RFM69HCW, RFM69_IRQN);
|
|
|
|
|
|
if (!radio.initialize(pGC->rfmfrequency, pGC->nodeid, pGC->networkid)) {
|
|
Log.error(F("ZgatewayRFM69 initialization failed" CR));
|
|
}
|
|
|
|
if (GC_IS_RFM69HCW) {
|
|
radio.setHighPower();
|
|
}
|
|
radio.setPowerLevel(GC_POWER_LEVEL);
|
|
|
|
if (pGC->encryptkey[0] != '\0')
|
|
radio.encrypt(pGC->encryptkey);
|
|
|
|
switch (pGC->rfmfrequency) {
|
|
case RF69_433MHZ:
|
|
freq = 433;
|
|
break;
|
|
case RF69_868MHZ:
|
|
freq = 868;
|
|
break;
|
|
case RF69_915MHZ:
|
|
freq = 915;
|
|
break;
|
|
case RF69_315MHZ:
|
|
freq = 315;
|
|
break;
|
|
default:
|
|
freq = -1;
|
|
break;
|
|
}
|
|
Log.notice(F("ZgatewayRFM69 Listening and transmitting at: %d" CR), freq);
|
|
|
|
size_t len = snprintf_P(RadioConfig, sizeof(RadioConfig), JSONtemplate,
|
|
freq, GC_IS_RFM69HCW, pGC->networkid, GC_POWER_LEVEL);
|
|
if (len >= sizeof(RadioConfig)) {
|
|
Log.trace(F("\n\n*** RFM69 config truncated ***\n" CR));
|
|
}
|
|
}
|
|
|
|
bool RFM69toMQTT(void) {
|
|
|
|
if (radio.receiveDone()) {
|
|
Log.trace(F("Creating RFM69 buffer" CR));
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject RFM69data = jsonBuffer.to<JsonObject>();
|
|
uint8_t data[RF69_MAX_DATA_LEN + 1];
|
|
uint8_t SENDERID = radio.SENDERID;
|
|
uint8_t DATALEN = radio.DATALEN;
|
|
uint16_t RSSI = radio.RSSI;
|
|
|
|
|
|
memcpy(data, (void*)radio.DATA, DATALEN);
|
|
data[DATALEN] = '\0';
|
|
|
|
|
|
|
|
if (radio.ACKRequested()) {
|
|
radio.sendACK();
|
|
}
|
|
|
|
|
|
Log.trace(F("Data received: %s" CR), (const char*)data);
|
|
|
|
char buff[sizeof(subjectRFM69toMQTT) + 4];
|
|
sprintf(buff, "%s/%d", subjectRFM69toMQTT, SENDERID);
|
|
RFM69data["data"] = (char*)data;
|
|
RFM69data["rssi"] = (int)radio.RSSI;
|
|
RFM69data["senderid"] = (int)radio.SENDERID;
|
|
pub(buff, RFM69data);
|
|
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
# if simpleReceiving
|
|
void MQTTtoRFM69(char* topicOri, char* datacallback) {
|
|
if (cmpToMainTopic(topicOri, subjectMQTTtoRFM69)) {
|
|
Log.trace(F("MQTTtoRFM69 data analysis" CR));
|
|
char data[RF69_MAX_DATA_LEN + 1];
|
|
memcpy(data, (void*)datacallback, RF69_MAX_DATA_LEN);
|
|
data[RF69_MAX_DATA_LEN] = '\0';
|
|
|
|
|
|
String topic = topicOri;
|
|
int valueRCV = defaultRFM69ReceiverId;
|
|
int pos = topic.lastIndexOf(RFM69receiverKey);
|
|
if (pos != -1) {
|
|
pos = pos + +strlen(RFM69receiverKey);
|
|
valueRCV = (topic.substring(pos, pos + 3)).toInt();
|
|
Log.notice(F("RFM69 receiver ID: %d" CR), valueRCV);
|
|
}
|
|
if (radio.sendWithRetry(valueRCV, data, strlen(data), 10)) {
|
|
Log.notice(F(" OK " CR));
|
|
|
|
char buff[sizeof(subjectGTWRFM69toMQTT) + 4];
|
|
sprintf(buff, "%s/%d", subjectGTWRFM69toMQTT, radio.SENDERID);
|
|
pub(buff, data);
|
|
} else {
|
|
Log.error(F("RFM69 sending failed" CR));
|
|
}
|
|
}
|
|
}
|
|
# endif
|
|
# if jsonReceiving
|
|
void MQTTtoRFM69(char* topicOri, JsonObject& RFM69data) {
|
|
if (cmpToMainTopic(topicOri, subjectMQTTtoRFM69)) {
|
|
const char* data = RFM69data["data"];
|
|
Log.trace(F("MQTTtoRFM69 json data analysis" CR));
|
|
if (data) {
|
|
Log.trace(F("MQTTtoRFM69 data ok" CR));
|
|
int valueRCV = RFM69data["receiverid"] | defaultRFM69ReceiverId;
|
|
Log.notice(F("RFM69 receiver ID: %d" CR), valueRCV);
|
|
if (radio.sendWithRetry(valueRCV, data, strlen(data), 10)) {
|
|
Log.notice(F(" OK " CR));
|
|
|
|
pub(subjectGTWRFM69toMQTT, RFM69data);
|
|
} else {
|
|
Log.error(F("MQTTtoRFM69 sending failed" CR));
|
|
}
|
|
} else {
|
|
Log.error(F("MQTTtoRFM69 failed json read" CR));
|
|
}
|
|
}
|
|
}
|
|
# endif
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayRS232.ino"
|
|
# 28 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayRS232.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZgatewayRS232
|
|
|
|
# include <SoftwareSerial.h>
|
|
|
|
SoftwareSerial RS232Serial(RS232_RX_GPIO, RS232_TX_GPIO);
|
|
|
|
void setupRS232() {
|
|
|
|
pinMode(RS232_RX_GPIO, INPUT);
|
|
pinMode(RS232_TX_GPIO, OUTPUT);
|
|
|
|
RS232Serial.begin(RS232Baud);
|
|
|
|
Log.notice(F("RS232_RX_GPIO: %d " CR), RS232_RX_GPIO);
|
|
Log.notice(F("RS232_TX_GPIO: %d " CR), RS232_TX_GPIO);
|
|
Log.notice(F("RS232Baud: %d " CR), RS232Baud);
|
|
Log.trace(F("ZgatewayRS232 setup done " CR));
|
|
}
|
|
|
|
void RS232toMQTT() {
|
|
|
|
if (RS232Serial.available()) {
|
|
Log.trace(F("RS232toMQTT" CR));
|
|
static char RS232data[MAX_INPUT];
|
|
static unsigned int input_pos = 0;
|
|
static char inChar;
|
|
do {
|
|
if (RS232Serial.available()) {
|
|
inChar = RS232Serial.read();
|
|
RS232data[input_pos] = inChar;
|
|
input_pos++;
|
|
Log.trace(F("Received %c" CR), inChar);
|
|
}
|
|
} while (inChar != RS232InPost && input_pos < MAX_INPUT);
|
|
RS232data[input_pos] = 0;
|
|
input_pos = 0;
|
|
Log.trace(F("Publish %s" CR), RS232data);
|
|
char* output = RS232data + sizeof(RS232Pre) - 1;
|
|
pub(subjectRS232toMQTT, output);
|
|
}
|
|
}
|
|
|
|
void MQTTtoRS232(char* topicOri, JsonObject& RS232data) {
|
|
Log.trace(F("json" CR));
|
|
if (cmpToMainTopic(topicOri, subjectMQTTtoRS232)) {
|
|
Log.trace(F("MQTTtoRS232 json" CR));
|
|
const char* data = RS232data["value"];
|
|
const char* prefix = RS232data["prefix"] | RS232Pre;
|
|
const char* postfix = RS232data["postfix"] | RS232Post;
|
|
Log.trace(F("Value set: %s" CR), data);
|
|
Log.trace(F("Prefix set: %s" CR), prefix);
|
|
Log.trace(F("Postfix set: %s" CR), postfix);
|
|
RS232Serial.print(prefix);
|
|
RS232Serial.print(data);
|
|
RS232Serial.print(postfix);
|
|
}
|
|
}
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayRTL_433.ino"
|
|
# 29 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayRTL_433.ino"
|
|
#include "User_config.h"
|
|
#ifdef ZgatewayRTL_433
|
|
# ifndef ZradioCC1101
|
|
# error "CC1101 is the only supported receiver module for RTL_433 and needs to be enabled."
|
|
# endif
|
|
|
|
# include <rtl_433_ESP.h>
|
|
|
|
char messageBuffer[JSON_MSG_BUFFER];
|
|
|
|
rtl_433_ESP rtl_433(-1);
|
|
|
|
# include <ELECHOUSE_CC1101_SRC_DRV.h>
|
|
|
|
void rtl_433_Callback(char* message) {
|
|
DynamicJsonDocument jsonBuffer2(JSON_MSG_BUFFER);
|
|
JsonObject RFrtl_433_ESPdata = jsonBuffer2.to<JsonObject>();
|
|
auto error = deserializeJson(jsonBuffer2, message);
|
|
if (error) {
|
|
Log.error(F("deserializeJson() failed: %s" CR), error.c_str());
|
|
return;
|
|
}
|
|
|
|
String topic = String(subjectRTL_433toMQTT);
|
|
# if valueAsATopic
|
|
String model = RFrtl_433_ESPdata["model"];
|
|
String id = RFrtl_433_ESPdata["id"];
|
|
if (model != 0) {
|
|
topic = topic + "/" + model;
|
|
if (id != 0) {
|
|
topic = topic + "/" + id;
|
|
}
|
|
}
|
|
# endif
|
|
|
|
pub((char*)topic.c_str(), RFrtl_433_ESPdata);
|
|
# ifdef MEMORY_DEBUG
|
|
Log.trace(F("Post rtl_433_Callback: %d" CR), ESP.getFreeHeap());
|
|
# endif
|
|
}
|
|
|
|
void setupRTL_433() {
|
|
rtl_433.initReceiver(RF_RECEIVER_GPIO, receiveMhz);
|
|
rtl_433.setCallback(rtl_433_Callback, messageBuffer, JSON_MSG_BUFFER);
|
|
Log.trace(F("ZgatewayRTL_433 command topic: %s%s%s" CR), mqtt_topic, gateway_name, subjectMQTTtoRTL_433);
|
|
Log.notice(F("ZgatewayRTL_433 setup done " CR));
|
|
}
|
|
|
|
void RTL_433Loop() {
|
|
rtl_433.loop();
|
|
}
|
|
|
|
extern void MQTTtoRTL_433(char* topicOri, JsonObject& RTLdata) {
|
|
if (cmpToMainTopic(topicOri, subjectMQTTtoRTL_433)) {
|
|
float tempMhz = RTLdata["mhz"];
|
|
bool success = false;
|
|
if (RTLdata.containsKey("mhz") && validFrequency(tempMhz)) {
|
|
receiveMhz = tempMhz;
|
|
Log.notice(F("RTL_433 Receive mhz: %F" CR), receiveMhz);
|
|
success = true;
|
|
}
|
|
if (RTLdata.containsKey("active")) {
|
|
Log.trace(F("RTL_433 active:" CR));
|
|
activeReceiver = ACTIVE_RTL;
|
|
success = true;
|
|
}
|
|
if (RTLdata.containsKey("rssi")) {
|
|
int minimumRssi = RTLdata["rssi"] | 0;
|
|
Log.notice(F("RTL_433 minimum RSSI: %d" CR), minimumRssi);
|
|
rtl_433.setMinimumRSSI(minimumRssi);
|
|
success = true;
|
|
}
|
|
if (RTLdata.containsKey("debug")) {
|
|
int debug = RTLdata["debug"] | -1;
|
|
Log.notice(F("RTL_433 set debug: %d" CR), debug);
|
|
rtl_433.setDebug(debug);
|
|
rtl_433.initReceiver(RF_RECEIVER_GPIO, receiveMhz);
|
|
success = true;
|
|
}
|
|
if (RTLdata.containsKey("status")) {
|
|
Log.notice(F("RTL_433 get status:" CR));
|
|
rtl_433.getStatus(1);
|
|
success = true;
|
|
}
|
|
if (success) {
|
|
pub(subjectRTL_433toMQTT, RTLdata);
|
|
} else {
|
|
pub(subjectRTL_433toMQTT, "{\"Status\": \"Error\"}");
|
|
Log.error(F("MQTTtoRTL_433 Fail json" CR));
|
|
}
|
|
enableActiveReceiver(false);
|
|
}
|
|
}
|
|
|
|
extern void enableRTLreceive() {
|
|
Log.notice(F("Switching to RTL_433 Receiver: %FMhz" CR), receiveMhz);
|
|
# ifdef ZgatewayRF
|
|
disableRFReceive();
|
|
# endif
|
|
# ifdef ZgatewayRF2
|
|
disableRF2Receive();
|
|
# endif
|
|
# ifdef ZgatewayPilight
|
|
disablePilightReceive();
|
|
# endif
|
|
ELECHOUSE_cc1101.SetRx(receiveMhz);
|
|
rtl_433.enableReceiver(RF_RECEIVER_GPIO);
|
|
pinMode(RF_EMITTER_GPIO, OUTPUT);
|
|
}
|
|
|
|
extern void disableRTLreceive() {
|
|
Log.trace(F("disableRTLreceive" CR));
|
|
rtl_433.enableReceiver(-1);
|
|
rtl_433.disableReceiver();
|
|
}
|
|
|
|
extern int getRTLMinimumRSSI() {
|
|
return rtl_433.minimumRssi;
|
|
}
|
|
|
|
extern int getRTLCurrentRSSI() {
|
|
return rtl_433.currentRssi;
|
|
}
|
|
|
|
extern int getRTLMessageCount() {
|
|
return rtl_433.messageCount;
|
|
}
|
|
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewaySRFB.ino"
|
|
# 31 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewaySRFB.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZgatewaySRFB
|
|
|
|
unsigned char _uartbuf[RF_MESSAGE_SIZE + 3] = {0};
|
|
unsigned char _uartpos = 0;
|
|
|
|
void setupSRFB() {
|
|
Log.trace(F("ZgatewaySRFB setup done " CR));
|
|
Log.trace(F("Serial Baud: %l" CR), SERIAL_BAUD);
|
|
}
|
|
|
|
void _rfbSend(byte* message) {
|
|
Serial.println();
|
|
Serial.write(RF_CODE_START);
|
|
Serial.write(RF_CODE_RFOUT);
|
|
for (unsigned char j = 0; j < RF_MESSAGE_SIZE; j++) {
|
|
Serial.write(message[j]);
|
|
}
|
|
Serial.write(RF_CODE_STOP);
|
|
Serial.flush();
|
|
Serial.println();
|
|
}
|
|
|
|
void _rfbSend(byte* message, int times) {
|
|
char buffer[RF_MESSAGE_SIZE];
|
|
_rfbToChar(message, buffer);
|
|
Log.notice(F("[RFBRIDGE] Sending MESSAGE" CR));
|
|
|
|
for (int i = 0; i < times; i++) {
|
|
if (i > 0) {
|
|
unsigned long start = millis();
|
|
while (millis() - start < RF_SEND_DELAY)
|
|
delay(1);
|
|
}
|
|
_rfbSend(message);
|
|
}
|
|
}
|
|
|
|
bool SRFBtoMQTT() {
|
|
static bool receiving = false;
|
|
|
|
while (Serial.available()) {
|
|
yield();
|
|
byte c = Serial.read();
|
|
|
|
if (receiving) {
|
|
if (c == RF_CODE_STOP) {
|
|
_rfbDecode();
|
|
receiving = false;
|
|
} else {
|
|
_uartbuf[_uartpos++] = c;
|
|
}
|
|
} else if (c == RF_CODE_START) {
|
|
_uartpos = 0;
|
|
receiving = true;
|
|
}
|
|
}
|
|
return receiving;
|
|
}
|
|
|
|
void _rfbDecode() {
|
|
static unsigned long last = 0;
|
|
if (millis() - last < RF_RECEIVE_DELAY)
|
|
return;
|
|
last = millis();
|
|
|
|
byte action = _uartbuf[0];
|
|
char buffer[RF_MESSAGE_SIZE * 2 + 1] = {0};
|
|
|
|
if (action == RF_CODE_RFIN) {
|
|
_rfbToChar(&_uartbuf[1], buffer);
|
|
|
|
Log.trace(F("Creating SRFB buffer" CR));
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject SRFBdata = jsonBuffer.to<JsonObject>();
|
|
SRFBdata["raw"] = String(buffer).substring(0, 18);
|
|
|
|
int val_Tsyn = (int)(int)value_from_hex_data(buffer, 0, 4, false, false);
|
|
SRFBdata["delay"] = (int)val_Tsyn;
|
|
|
|
int val_Tlow = (int)value_from_hex_data(buffer, 4, 4, false, false);
|
|
SRFBdata["val_Tlow"] = (int)val_Tlow;
|
|
|
|
int val_Thigh = (int)value_from_hex_data(buffer, 8, 4, false, false);
|
|
SRFBdata["val_Thigh"] = (int)val_Thigh;
|
|
|
|
unsigned long MQTTvalue = (unsigned long)value_from_hex_data(buffer, 12, 8, false, false);
|
|
SRFBdata["value"] = (unsigned long)MQTTvalue;
|
|
|
|
if (!isAduplicateSignal(MQTTvalue) && MQTTvalue != 0) {
|
|
Log.trace(F("Adv data SRFBtoMQTT" CR));
|
|
pub(subjectSRFBtoMQTT, SRFBdata);
|
|
Log.trace(F("Store val: %lu" CR), MQTTvalue);
|
|
storeSignalValue(MQTTvalue);
|
|
if (repeatSRFBwMQTT) {
|
|
Log.trace(F("Publish SRFB for rpt" CR));
|
|
pub(subjectMQTTtoSRFB, SRFBdata);
|
|
}
|
|
}
|
|
_rfbAck();
|
|
}
|
|
}
|
|
|
|
void _rfbAck() {
|
|
Log.trace(F("[RFBRIDGE] Sending ACK\n" CR));
|
|
Serial.println();
|
|
Serial.write(RF_CODE_START);
|
|
Serial.write(RF_CODE_ACK);
|
|
Serial.write(RF_CODE_STOP);
|
|
Serial.flush();
|
|
Serial.println();
|
|
}
|
|
|
|
|
|
|
|
|
|
bool _rfbToArray(const char* in, byte* out) {
|
|
if (strlen(in) != RF_MESSAGE_SIZE * 2)
|
|
return false;
|
|
char tmp[3] = {0};
|
|
for (unsigned char p = 0; p < RF_MESSAGE_SIZE; p++) {
|
|
memcpy(tmp, &in[p * 2], 2);
|
|
out[p] = strtol(tmp, NULL, 16);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
bool _rfbToChar(byte* in, char* out) {
|
|
for (unsigned char p = 0; p < RF_MESSAGE_SIZE; p++) {
|
|
sprintf_P(&out[p * 2], PSTR("%02X" CR), in[p]);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
# if simpleReceiving
|
|
void MQTTtoSRFB(char* topicOri, char* datacallback) {
|
|
|
|
String topic = topicOri;
|
|
int valueRPT = 0;
|
|
|
|
if (topic == subjectMQTTtoSRFB) {
|
|
int valueMiniPLSL = 0;
|
|
int valueMaxiPLSL = 0;
|
|
int valueSYNC = 0;
|
|
|
|
int pos = topic.lastIndexOf(SRFBRptKey);
|
|
if (pos != -1) {
|
|
pos = pos + +strlen(SRFBRptKey);
|
|
valueRPT = (topic.substring(pos, pos + 1)).toInt();
|
|
Log.notice(F("SRFB Repeat: %d" CR), valueRPT);
|
|
}
|
|
|
|
int pos2 = topic.lastIndexOf(SRFBminipulselengthKey);
|
|
if (pos2 != -1) {
|
|
pos2 = pos2 + strlen(SRFBminipulselengthKey);
|
|
valueMiniPLSL = (topic.substring(pos2, pos2 + 3)).toInt();
|
|
Log.notice(F("RF Mini Pulse Lgth: %d" CR), valueMiniPLSL);
|
|
}
|
|
|
|
int pos3 = topic.lastIndexOf(SRFBmaxipulselengthKey);
|
|
if (pos3 != -1) {
|
|
pos3 = pos3 + strlen(SRFBmaxipulselengthKey);
|
|
valueMaxiPLSL = (topic.substring(pos3, pos3 + 2)).toInt();
|
|
Log.notice(F("RF Maxi Pulse Lgth: %d" CR), valueMaxiPLSL);
|
|
}
|
|
|
|
int pos4 = topic.lastIndexOf(SRFBsyncKey);
|
|
if (pos4 != -1) {
|
|
pos4 = pos4 + strlen(SRFBsyncKey);
|
|
valueSYNC = (topic.substring(pos4, pos4 + 2)).toInt();
|
|
Log.notice(F("RF sync: %d" CR), valueSYNC);
|
|
}
|
|
|
|
Log.trace(F("MQTTtoSRFB prts" CR));
|
|
if (valueRPT == 0)
|
|
valueRPT = 1;
|
|
if (valueMiniPLSL == 0)
|
|
valueMiniPLSL = 320;
|
|
if (valueMaxiPLSL == 0)
|
|
valueMaxiPLSL = 900;
|
|
if (valueSYNC == 0)
|
|
valueSYNC = 9500;
|
|
|
|
byte hex_valueMiniPLSL[2];
|
|
hex_valueMiniPLSL[0] = (int)((valueMiniPLSL >> 8) & 0xFF);
|
|
hex_valueMiniPLSL[1] = (int)(valueMiniPLSL & 0xFF);
|
|
|
|
byte hex_valueMaxiPLSL[2];
|
|
hex_valueMaxiPLSL[0] = (int)((valueMaxiPLSL >> 8) & 0xFF);
|
|
hex_valueMaxiPLSL[1] = (int)(valueMaxiPLSL & 0xFF);
|
|
|
|
byte hex_valueSYNC[2];
|
|
hex_valueSYNC[0] = (int)((valueSYNC >> 8) & 0xFF);
|
|
hex_valueSYNC[1] = (int)(valueSYNC & 0xFF);
|
|
|
|
unsigned long data = strtoul(datacallback, NULL, 10);
|
|
byte hex_data[3];
|
|
hex_data[0] = (unsigned long)((data >> 16) & 0xFF);
|
|
hex_data[1] = (unsigned long)((data >> 8) & 0xFF);
|
|
hex_data[2] = (unsigned long)(data & 0xFF);
|
|
|
|
byte message_b[RF_MESSAGE_SIZE];
|
|
|
|
memcpy(message_b, hex_valueSYNC, 2);
|
|
memcpy(message_b + 2, hex_valueMiniPLSL, 2);
|
|
memcpy(message_b + 4, hex_valueMaxiPLSL, 2);
|
|
memcpy(message_b + 6, hex_data, 3);
|
|
|
|
_rfbSend(message_b, valueRPT);
|
|
|
|
pub(subjectGTWSRFBtoMQTT, datacallback);
|
|
}
|
|
if (topic == subjectMQTTtoSRFBRaw) {
|
|
int pos = topic.lastIndexOf(SRFBRptKey);
|
|
if (pos != -1) {
|
|
pos = pos + +strlen(SRFBRptKey);
|
|
valueRPT = (topic.substring(pos, pos + 1)).toInt();
|
|
Log.notice(F("SRFB Repeat: %d" CR), valueRPT);
|
|
}
|
|
if (valueRPT == 0)
|
|
valueRPT = 1;
|
|
|
|
byte message_b[RF_MESSAGE_SIZE];
|
|
_rfbToArray(datacallback, message_b);
|
|
_rfbSend(message_b, valueRPT);
|
|
|
|
pub(subjectGTWSRFBtoMQTT, datacallback);
|
|
}
|
|
}
|
|
# endif
|
|
# if jsonReceiving
|
|
void MQTTtoSRFB(char* topicOri, JsonObject& SRFBdata) {
|
|
|
|
const char* raw = SRFBdata["raw"];
|
|
int valueRPT = SRFBdata["repeat"] | 1;
|
|
if (cmpToMainTopic(topicOri, subjectMQTTtoSRFB)) {
|
|
Log.trace(F("MQTTtoSRFB json" CR));
|
|
if (raw) {
|
|
Log.trace(F("MQTTtoSRFB raw ok" CR));
|
|
byte message_b[RF_MESSAGE_SIZE];
|
|
_rfbToArray(raw, message_b);
|
|
_rfbSend(message_b, valueRPT);
|
|
} else {
|
|
unsigned long data = SRFBdata["value"];
|
|
if (data != 0) {
|
|
Log.notice(F("MQTTtoSRFB data ok" CR));
|
|
int valueMiniPLSL = SRFBdata["val_Tlow"];
|
|
int valueMaxiPLSL = SRFBdata["val_Thigh"];
|
|
int valueSYNC = SRFBdata["delay"];
|
|
|
|
if (valueRPT == 0)
|
|
valueRPT = 1;
|
|
if (valueMiniPLSL == 0)
|
|
valueMiniPLSL = 320;
|
|
if (valueMaxiPLSL == 0)
|
|
valueMaxiPLSL = 900;
|
|
if (valueSYNC == 0)
|
|
valueSYNC = 9500;
|
|
|
|
Log.notice(F("SRFB Repeat: %d" CR), valueRPT);
|
|
Log.notice(F("RF Mini Pulse Lgth: %d" CR), valueMiniPLSL);
|
|
Log.notice(F("RF Maxi Pulse Lgth: %d" CR), valueMaxiPLSL);
|
|
Log.notice(F("RF sync: %d" CR), valueSYNC);
|
|
|
|
byte hex_valueMiniPLSL[2];
|
|
hex_valueMiniPLSL[0] = (int)((valueMiniPLSL >> 8) & 0xFF);
|
|
hex_valueMiniPLSL[1] = (int)(valueMiniPLSL & 0xFF);
|
|
|
|
byte hex_valueMaxiPLSL[2];
|
|
hex_valueMaxiPLSL[0] = (int)((valueMaxiPLSL >> 8) & 0xFF);
|
|
hex_valueMaxiPLSL[1] = (int)(valueMaxiPLSL & 0xFF);
|
|
|
|
byte hex_valueSYNC[2];
|
|
hex_valueSYNC[0] = (int)((valueSYNC >> 8) & 0xFF);
|
|
hex_valueSYNC[1] = (int)(valueSYNC & 0xFF);
|
|
|
|
byte hex_data[3];
|
|
hex_data[0] = (unsigned long)((data >> 16) & 0xFF);
|
|
hex_data[1] = (unsigned long)((data >> 8) & 0xFF);
|
|
hex_data[2] = (unsigned long)(data & 0xFF);
|
|
|
|
byte message_b[RF_MESSAGE_SIZE];
|
|
|
|
memcpy(message_b, hex_valueSYNC, 2);
|
|
memcpy(message_b + 2, hex_valueMiniPLSL, 2);
|
|
memcpy(message_b + 4, hex_valueMaxiPLSL, 2);
|
|
memcpy(message_b + 6, hex_data, 3);
|
|
|
|
Log.notice(F("MQTTtoSRFB OK" CR));
|
|
_rfbSend(message_b, valueRPT);
|
|
|
|
pub(subjectGTWSRFBtoMQTT, SRFBdata);
|
|
} else {
|
|
Log.error(F("MQTTtoSRFB error decoding value" CR));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
# endif
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayWeatherStation.ino"
|
|
# 26 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZgatewayWeatherStation.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZgatewayWeatherStation
|
|
# include <WeatherStationDataRx.h>
|
|
WeatherStationDataRx wsdr(RF_WS_RECEIVER_GPIO, true);
|
|
|
|
void PairedDeviceAdded(byte newID) {
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
Serial.printf("ZgatewayWeatherStation: New device paired %d\r\n", newID);
|
|
# else
|
|
Serial.print("ZgatewayWeatherStation: New device paired ");
|
|
Serial.println(newID, DEC);
|
|
# endif
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject RFdata = jsonBuffer.to<JsonObject>();
|
|
RFdata["sensor"] = newID;
|
|
RFdata["action"] = "paired";
|
|
pub(subjectRFtoMQTT, RFdata);
|
|
wsdr.pair(NULL, PairedDeviceAdded);
|
|
}
|
|
|
|
void setupWeatherStation() {
|
|
Log.notice(F("RF_WS_RECEIVER_GPIO %d" CR), RF_WS_RECEIVER_GPIO);
|
|
wsdr.begin();
|
|
wsdr.pair(NULL, PairedDeviceAdded);
|
|
Log.trace(F("ZgatewayWeatherStation setup done " CR));
|
|
}
|
|
|
|
void sendWindSpeedData(byte id, float wind_speed, byte battery_status) {
|
|
unsigned long MQTTvalue = 10000 + round(wind_speed);
|
|
if (!isAduplicateSignal(MQTTvalue)) {
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject RFdata = jsonBuffer.to<JsonObject>();
|
|
RFdata["sensor"] = id;
|
|
RFdata["wind_speed"] = wind_speed;
|
|
RFdata["battery"] = bitRead(battery_status, 0) == 0 ? "OK" : "Low";
|
|
pub(subjectRFtoMQTT, RFdata);
|
|
Log.trace(F("Store wind speed val: %lu" CR), MQTTvalue);
|
|
storeSignalValue(MQTTvalue);
|
|
}
|
|
}
|
|
|
|
void sendRainData(byte id, float rain_volume, byte battery_status) {
|
|
unsigned long MQTTvalue = 11000 + round(rain_volume * 10.0);
|
|
if (!isAduplicateSignal(MQTTvalue)) {
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject RFdata = jsonBuffer.to<JsonObject>();
|
|
RFdata["sensor"] = id;
|
|
RFdata["rain_volume"] = rain_volume;
|
|
RFdata["battery"] = bitRead(battery_status, 1) == 0 ? "OK" : "Low";
|
|
pub(subjectRFtoMQTT, RFdata);
|
|
Log.trace(F("Store rain_volume: %lu" CR), MQTTvalue);
|
|
storeSignalValue(MQTTvalue);
|
|
}
|
|
}
|
|
|
|
void sendWindData(byte id, int wind_direction, float wind_gust, byte battery_status) {
|
|
unsigned long MQTTvalue = 20000 + round(wind_gust * 10.0) + wind_direction;
|
|
if (!isAduplicateSignal(MQTTvalue)) {
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject RFdata = jsonBuffer.to<JsonObject>();
|
|
RFdata["sensor"] = id;
|
|
RFdata["wind_direction"] = wind_direction;
|
|
RFdata["wind_gust"] = wind_gust;
|
|
RFdata["battery"] = bitRead(battery_status, 0) == 0 ? "OK" : "Low";
|
|
pub(subjectRFtoMQTT, RFdata);
|
|
Log.trace(F("Store wind data val: %lu" CR), MQTTvalue);
|
|
storeSignalValue(MQTTvalue);
|
|
}
|
|
}
|
|
|
|
void sendTemperatureData(byte id, float temperature, int humidity, byte battery_status) {
|
|
unsigned long MQTTvalue = 40000 + abs(round(temperature * 100.0)) + humidity;
|
|
if (!isAduplicateSignal(MQTTvalue)) {
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject RFdata = jsonBuffer.to<JsonObject>();
|
|
RFdata["sensor"] = id;
|
|
RFdata["tempc"] = temperature;
|
|
RFdata["tempf"] = wsdr.convertCtoF(temperature);
|
|
RFdata["humidity"] = humidity;
|
|
RFdata["battery"] = bitRead(battery_status, 0) == 0 ? "OK" : "Low";
|
|
pub(subjectRFtoMQTT, RFdata);
|
|
Log.trace(F("Store temp val: %lu" CR), MQTTvalue);
|
|
storeSignalValue(MQTTvalue);
|
|
}
|
|
}
|
|
|
|
void ZgatewayWeatherStationtoMQTT() {
|
|
char newData = wsdr.readData();
|
|
switch (newData) {
|
|
case 'T':
|
|
Log.trace(F("Temperature" CR));
|
|
sendTemperatureData(wsdr.sensorID(), wsdr.readTemperature(), wsdr.readHumidity(), wsdr.batteryStatus());
|
|
break;
|
|
|
|
case 'S':
|
|
Log.trace(F("Wind speed" CR));
|
|
sendWindSpeedData(wsdr.sensorID(), wsdr.readWindSpeed(), wsdr.batteryStatus());
|
|
break;
|
|
|
|
case 'G':
|
|
Log.trace(F("Wind direction" CR));
|
|
sendWindData(wsdr.sensorID(), wsdr.readWindDirection(), wsdr.readWindGust(), wsdr.batteryStatus());
|
|
break;
|
|
|
|
case 'R':
|
|
Log.trace(F("Rain volume" CR));
|
|
sendRainData(wsdr.sensorID(), wsdr.readRainVolume(), wsdr.batteryStatus());
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZmqttDiscovery.ino"
|
|
# 26 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZmqttDiscovery.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZmqttDiscovery
|
|
|
|
String getMacAddress() {
|
|
uint8_t baseMac[6];
|
|
char baseMacChr[13] = {0};
|
|
# if defined(ESP8266)
|
|
WiFi.macAddress(baseMac);
|
|
sprintf(baseMacChr, "%02X%02X%02X%02X%02X%02X", baseMac[0], baseMac[1], baseMac[2], baseMac[3], baseMac[4], baseMac[5]);
|
|
# elif defined(ESP32)
|
|
esp_read_mac(baseMac, ESP_MAC_WIFI_STA);
|
|
sprintf(baseMacChr, "%02X%02X%02X%02X%02X%02X", baseMac[0], baseMac[1], baseMac[2], baseMac[3], baseMac[4], baseMac[5]);
|
|
# else
|
|
sprintf(baseMacChr, "%02X%02X%02X%02X%02X%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
|
# endif
|
|
return String(baseMacChr);
|
|
}
|
|
|
|
String getUniqueId(String name, String sufix) {
|
|
String uniqueId = (String)getMacAddress() + "-" + name + sufix;
|
|
return String(uniqueId);
|
|
}
|
|
|
|
# ifdef ZgatewayBT
|
|
# 69 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZmqttDiscovery.ino"
|
|
void createDiscoveryFromList(const char* mac,
|
|
const char* sensorList[][9],
|
|
int sensorCount,
|
|
const char* device_name,
|
|
const char* device_manufacturer,
|
|
const char* device_model) {
|
|
for (int i = 0; i < sensorCount; i++) {
|
|
String discovery_topic = String(subjectBTtoMQTT) + "/" + String(mac);
|
|
String unique_id = String(mac) + "-" + sensorList[i][1];
|
|
|
|
createDiscovery(sensorList[i][0],
|
|
discovery_topic.c_str(), sensorList[i][1], unique_id.c_str(),
|
|
will_Topic, sensorList[i][3], sensorList[i][4],
|
|
sensorList[i][5], sensorList[i][6], sensorList[i][7],
|
|
0, "", "", false, "",
|
|
device_name, device_manufacturer, device_model, mac, false,
|
|
sensorList[i][8]
|
|
);
|
|
}
|
|
}
|
|
# endif
|
|
# 103 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZmqttDiscovery.ino"
|
|
void announceDeviceTrigger(bool use_gateway_info, char* topic, char* type, char* subtype, char* unique_id, char* device_name, char* device_manufacturer, char* device_model, char* device_mac) {
|
|
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject sensor = jsonBuffer.to<JsonObject>();
|
|
|
|
|
|
sensor["automation_type"] = "trigger";
|
|
|
|
|
|
if (type[0] != 0) {
|
|
sensor["type"] = type;
|
|
} else {
|
|
sensor["type"] = "button_short_press";
|
|
}
|
|
|
|
|
|
if (subtype[0] != 0) {
|
|
sensor["subtype"] = subtype;
|
|
} else {
|
|
sensor["subtype"] = "turn_on";
|
|
}
|
|
|
|
|
|
if (topic[0]) {
|
|
char state_topic[mqtt_topic_max_size];
|
|
|
|
strcpy(state_topic, mqtt_topic);
|
|
strcat(state_topic, gateway_name);
|
|
|
|
strcat(state_topic, topic);
|
|
sensor["topic"] = state_topic;
|
|
}
|
|
|
|
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonDeviceBuffer;
|
|
JsonObject device = jsonDeviceBuffer.to<JsonObject>();
|
|
JsonArray identifiers = device.createNestedArray("identifiers");
|
|
|
|
if (use_gateway_info) {
|
|
char JSONmessageBuffer[JSON_MSG_BUFFER];
|
|
serializeJson(modules, JSONmessageBuffer, sizeof(JSONmessageBuffer));
|
|
|
|
device["name"] = gateway_name;
|
|
device["model"] = JSONmessageBuffer;
|
|
device["manufacturer"] = DEVICEMANUFACTURER;
|
|
device["sw_version"] = OMG_VERSION;
|
|
identifiers.add(getMacAddress());
|
|
|
|
} else {
|
|
char deviceid[13];
|
|
memcpy(deviceid, &unique_id[0], 12);
|
|
deviceid[12] = '\0';
|
|
|
|
identifiers.add(deviceid);
|
|
|
|
|
|
if (device_mac[0] != 0) {
|
|
JsonArray connections = device.createNestedArray("connections");
|
|
JsonArray connection_mac = connections.createNestedArray();
|
|
connection_mac.add("mac");
|
|
connection_mac.add(device_mac);
|
|
}
|
|
|
|
|
|
if (device_manufacturer[0]) {
|
|
device["manufacturer"] = device_manufacturer;
|
|
}
|
|
|
|
|
|
if (device_name[0]) {
|
|
device["name"] = device_name;
|
|
}
|
|
|
|
|
|
if (device_model[0]) {
|
|
device["model"] = device_model;
|
|
}
|
|
|
|
device["via_device"] = gateway_name;
|
|
}
|
|
sensor["device"] = device;
|
|
|
|
|
|
String topic_to_publish = String(discovery_Topic) + "/device_automation/" + String(unique_id) + "/config";
|
|
Log.trace(F("Announce Device Trigger %s" CR), topic_to_publish.c_str());
|
|
pub_custom_topic((char*)topic_to_publish.c_str(), sensor, true);
|
|
}
|
|
# 217 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZmqttDiscovery.ino"
|
|
void createDiscovery(const char* sensor_type,
|
|
const char* st_topic, const char* s_name, const char* unique_id,
|
|
const char* availability_topic, const char* device_class, const char* value_template,
|
|
const char* payload_on, const char* payload_off, const char* unit_of_meas,
|
|
int off_delay,
|
|
const char* payload_available, const char* payload_not_avalaible, bool gateway_entity, const char* cmd_topic,
|
|
const char* device_name, const char* device_manufacturer, const char* device_model, const char* device_mac, bool retainCmd,
|
|
const char* state_class, const char* state_off, const char* state_on) {
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject sensor = jsonBuffer.to<JsonObject>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (st_topic[0]) {
|
|
char state_topic[mqtt_topic_max_size];
|
|
|
|
|
|
if (gateway_entity) {
|
|
strcpy(state_topic, mqtt_topic);
|
|
strcat(state_topic, gateway_name);
|
|
} else {
|
|
strcpy(state_topic, "+/+");
|
|
}
|
|
strcat(state_topic, st_topic);
|
|
sensor["stat_t"] = state_topic;
|
|
}
|
|
|
|
if (device_class[0]) {
|
|
|
|
int num_classes = sizeof(availableHASSClasses) / sizeof(availableHASSClasses[0]);
|
|
for (int i = 0; i < num_classes; i++) {
|
|
if (strcmp(availableHASSClasses[i], device_class) == 0) {
|
|
sensor["dev_cla"] = device_class;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (unit_of_meas[0]) {
|
|
|
|
int num_units = sizeof(availableHASSUnits) / sizeof(availableHASSUnits[0]);
|
|
for (int i = 0; i < num_units; i++) {
|
|
if (strcmp(availableHASSUnits[i], unit_of_meas) == 0) {
|
|
sensor["unit_of_meas"] = unit_of_meas;
|
|
}
|
|
}
|
|
}
|
|
sensor["name"] = s_name;
|
|
sensor["uniq_id"] = unique_id;
|
|
if (retainCmd)
|
|
sensor["retain"] = retainCmd;
|
|
if (value_template[0])
|
|
sensor["val_tpl"] = value_template;
|
|
if (payload_on[0])
|
|
sensor["pl_on"] = payload_on;
|
|
if (payload_off[0])
|
|
sensor["pl_off"] = payload_off;
|
|
if (off_delay != 0)
|
|
sensor["off_delay"] = off_delay;
|
|
if (payload_available[0])
|
|
sensor["pl_avail"] = payload_available;
|
|
if (payload_not_avalaible[0])
|
|
sensor["pl_not_avail"] = payload_not_avalaible;
|
|
if (state_class[0])
|
|
sensor["state_class"] = state_class;
|
|
if (state_on != nullptr)
|
|
sensor["stat_on"] = state_on;
|
|
if (state_off != nullptr)
|
|
sensor["stat_off"] = state_off;
|
|
|
|
if (cmd_topic[0]) {
|
|
char command_topic[mqtt_topic_max_size];
|
|
strcpy(command_topic, mqtt_topic);
|
|
strcat(command_topic, gateway_name);
|
|
strcat(command_topic, cmd_topic);
|
|
sensor["cmd_t"] = command_topic;
|
|
}
|
|
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonDeviceBuffer;
|
|
JsonObject device = jsonDeviceBuffer.to<JsonObject>();
|
|
JsonArray identifiers = device.createNestedArray("identifiers");
|
|
|
|
if (gateway_entity) {
|
|
|
|
String model = "";
|
|
serializeJson(modules, model);
|
|
device["name"] = String(gateway_name);
|
|
device["model"] = model;
|
|
device["manufacturer"] = DEVICEMANUFACTURER;
|
|
device["sw_version"] = OMG_VERSION;
|
|
identifiers.add(String(getMacAddress()));
|
|
} else {
|
|
|
|
|
|
char deviceid[13];
|
|
memcpy(deviceid, &unique_id[0], 12);
|
|
deviceid[12] = '\0';
|
|
identifiers.add(deviceid);
|
|
|
|
|
|
if (device_mac[0] != 0) {
|
|
JsonArray connections = device.createNestedArray("connections");
|
|
JsonArray connection_mac = connections.createNestedArray();
|
|
connection_mac.add("mac");
|
|
connection_mac.add(device_mac);
|
|
}
|
|
|
|
if (device_manufacturer[0]) {
|
|
device["manufacturer"] = device_manufacturer;
|
|
}
|
|
|
|
if (device_model[0]) {
|
|
device["model"] = device_model;
|
|
}
|
|
|
|
if (device_name[0]) {
|
|
|
|
device["name"] = device_name + String("-") + String(device_mac + 6);
|
|
}
|
|
|
|
device["via_device"] = String(gateway_name);
|
|
}
|
|
|
|
sensor["device"] = device;
|
|
|
|
String topic = String(discovery_Topic) + "/" + String(sensor_type) + "/" + String(unique_id) + "/config";
|
|
Log.trace(F("Announce Device %s on %s" CR), String(sensor_type).c_str(), topic.c_str());
|
|
pub_custom_topic((char*)topic.c_str(), sensor, true);
|
|
}
|
|
|
|
void pubMqttDiscovery() {
|
|
Log.trace(F("omgStatusDiscovery" CR));
|
|
createDiscovery("binary_sensor",
|
|
will_Topic, "SYS: Connectivity", (char*)getUniqueId("connectivity", "").c_str(),
|
|
will_Topic, "connectivity", "",
|
|
Gateway_AnnouncementMsg, will_Message, "",
|
|
0,
|
|
Gateway_AnnouncementMsg, will_Message, true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
createDiscovery("sensor",
|
|
subjectSYStoMQTT, "SYS: Uptime", (char*)getUniqueId("uptime", "").c_str(),
|
|
"", "", "{{ value_json.uptime }}",
|
|
"", "", "s",
|
|
0,
|
|
"", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
createDiscovery("sensor",
|
|
subjectSYStoMQTT, "SYS: Free memory", (char*)getUniqueId("freemem", "").c_str(),
|
|
"", "", "{{ value_json.freemem }}",
|
|
"", "", "B",
|
|
0,
|
|
"", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
createDiscovery("sensor",
|
|
subjectSYStoMQTT, "SYS: IP", (char*)getUniqueId("ip", "").c_str(),
|
|
"", "", "{{ value_json.ip }}",
|
|
"", "", "",
|
|
0,
|
|
"", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
# ifndef ESP32_ETHERNET
|
|
createDiscovery("sensor",
|
|
subjectSYStoMQTT, "SYS: Rssi", (char*)getUniqueId("rssi", "").c_str(),
|
|
"", "", "{{ value_json.rssi }}",
|
|
"", "", "dB",
|
|
0,
|
|
"", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
# endif
|
|
# endif
|
|
# ifdef ESP32
|
|
# ifdef ZgatewayBT
|
|
createDiscovery("sensor",
|
|
subjectSYStoMQTT, "SYS: Low Power Mode", (char*)getUniqueId("lowpowermode", "").c_str(),
|
|
"", "", "{{ value_json.lowpowermode }}",
|
|
"", "", "",
|
|
0,
|
|
"", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
# endif
|
|
# if defined(ZboardM5STICKC) || defined(ZboardM5STICKCP) || defined(ZboardM5TOUGH)
|
|
createDiscovery("sensor",
|
|
subjectSYStoMQTT, "SYS: Bat voltage", (char*)getUniqueId("m5batvoltage", "").c_str(),
|
|
"", "", "{{ value_json.m5batvoltage }}",
|
|
"", "", "V",
|
|
0,
|
|
"", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
createDiscovery("sensor",
|
|
subjectSYStoMQTT, "SYS: Bat current", (char*)getUniqueId("m5batcurrent", "").c_str(),
|
|
"", "", "{{ value_json.m5batcurrent }}",
|
|
"", "", "A",
|
|
0,
|
|
"", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
createDiscovery("sensor",
|
|
subjectSYStoMQTT, "SYS: Vin voltage", (char*)getUniqueId("m5vinvoltage", "").c_str(),
|
|
"", "", "{{ value_json.m5vinvoltage }}",
|
|
"", "", "V",
|
|
0,
|
|
"", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
createDiscovery("sensor",
|
|
subjectSYStoMQTT, "SYS: Vin current", (char*)getUniqueId("m5vincurrent", "").c_str(),
|
|
"", "", "{{ value_json.m5vincurrent }}",
|
|
"", "", "A",
|
|
0,
|
|
"", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
# endif
|
|
# ifdef ZboardM5STACK
|
|
createDiscovery("sensor",
|
|
subjectSYStoMQTT, "SYS: Batt level", (char*)getUniqueId("m5battlevel", "").c_str(),
|
|
"", "", "{{ value_json.m5battlevel }}",
|
|
"", "", "%",
|
|
0,
|
|
"", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
createDiscovery("binary_sensor",
|
|
subjectSYStoMQTT, "SYS: Is Charging", (char*)getUniqueId("m5ischarging", "").c_str(),
|
|
"", "{{ value_json.m5ischarging }}", "",
|
|
"", "", "%",
|
|
0,
|
|
"", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
createDiscovery("binary_sensor",
|
|
subjectSYStoMQTT, "SYS: Is Charge Full", (char*)getUniqueId("m5ischargefull", "").c_str(),
|
|
"", "{{ value_json.m5ischargefull }}", "",
|
|
"", "", "%",
|
|
0,
|
|
"", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
# endif
|
|
# endif
|
|
createDiscovery("switch",
|
|
will_Topic, "SYS: Restart gateway", (char*)getUniqueId("restart", "").c_str(),
|
|
will_Topic, "", "",
|
|
"{\"cmd\":\"restart\"}", "", "",
|
|
0,
|
|
Gateway_AnnouncementMsg, will_Message, true, subjectMQTTtoSYSset,
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
createDiscovery("switch",
|
|
will_Topic, "SYS: Erase credentials", (char*)getUniqueId("erase", "").c_str(),
|
|
will_Topic, "", "",
|
|
"{\"cmd\":\"erase\"}", "", "",
|
|
0,
|
|
Gateway_AnnouncementMsg, will_Message, true, subjectMQTTtoSYSset,
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
createDiscovery("switch",
|
|
"", "SYS: Auto discovery", (char*)getUniqueId("discovery", "").c_str(),
|
|
will_Topic, "", "",
|
|
"{\"discovery\":true}", "{\"discovery\":false}", "",
|
|
0,
|
|
Gateway_AnnouncementMsg, will_Message, true, subjectMQTTtoSYSset,
|
|
"", "", "", "", true,
|
|
stateClassNone
|
|
);
|
|
|
|
# ifdef ZsensorBME280
|
|
#define BMEparametersCount 5
|
|
Log.trace(F("bme280Discovery" CR));
|
|
char* BMEsensor[BMEparametersCount][8] = {
|
|
{"sensor", "temp", "bme", "temperature", jsonTempc, "", "", "°C"},
|
|
{"sensor", "pa", "bme", "", jsonPa, "", "", "hPa"},
|
|
{"sensor", "hum", "bme", "humidity", jsonHum, "", "", "%"},
|
|
{"sensor", "altim", "bme", "", jsonAltim, "", "", "m"},
|
|
{"sensor", "altift", "bme", "", jsonAltif, "", "", "ft"}
|
|
|
|
};
|
|
|
|
for (int i = 0; i < BMEparametersCount; i++) {
|
|
|
|
createDiscovery(BMEsensor[i][0],
|
|
BMETOPIC, BMEsensor[i][1], (char*)getUniqueId(BMEsensor[i][1], BMEsensor[i][2]).c_str(),
|
|
will_Topic, BMEsensor[i][3], BMEsensor[i][4],
|
|
BMEsensor[i][5], BMEsensor[i][6], BMEsensor[i][7],
|
|
0, "", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
}
|
|
# endif
|
|
|
|
# ifdef ZsensorHTU21
|
|
#define HTUparametersCount 2
|
|
Log.trace(F("htu21Discovery" CR));
|
|
char* HTUsensor[HTUparametersCount][8] = {
|
|
{"sensor", "temp", "htu", "temperature", jsonTempc, "", "", "°C"},
|
|
{"sensor", "hum", "htu", "humidity", jsonHum, "", "", "%"}
|
|
|
|
};
|
|
|
|
for (int i = 0; i < HTUparametersCount; i++) {
|
|
|
|
createDiscovery(HTUsensor[i][0],
|
|
HTUTOPIC, HTUsensor[i][1], (char*)getUniqueId(HTUsensor[i][1], HTUsensor[i][2]).c_str(),
|
|
will_Topic, HTUsensor[i][3], HTUsensor[i][4],
|
|
HTUsensor[i][5], HTUsensor[i][6], HTUsensor[i][7],
|
|
0, "", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
}
|
|
# endif
|
|
|
|
# ifdef ZsensorAHTx0
|
|
#define AHTparametersCount 2
|
|
Log.trace(F("AHTx0Discovery" CR));
|
|
char* AHTsensor[AHTparametersCount][8] = {
|
|
{"sensor", "temp", "aht", "temperature", jsonTempc, "", "", "°C"},
|
|
{"sensor", "hum", "aht", "humidity", jsonHum, "", "", "%"}
|
|
|
|
};
|
|
|
|
for (int i = 0; i < AHTparametersCount; i++) {
|
|
createDiscovery(AHTsensor[i][0],
|
|
AHTTOPIC, AHTsensor[i][1], (char*)getUniqueId(AHTsensor[i][1], AHTsensor[i][2]).c_str(),
|
|
will_Topic, AHTsensor[i][3], AHTsensor[i][4],
|
|
AHTsensor[i][5], AHTsensor[i][6], AHTsensor[i][7],
|
|
0, "", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
}
|
|
# endif
|
|
|
|
# ifdef ZsensorDHT
|
|
#define DHTparametersCount 2
|
|
Log.trace(F("DHTDiscovery" CR));
|
|
char* DHTsensor[DHTparametersCount][8] = {
|
|
{"sensor", "temp", "dht", "temperature", jsonTempc, "", "", "°C"},
|
|
{"sensor", "hum", "dht", "humidity", jsonHum, "", "", "%"}
|
|
|
|
};
|
|
|
|
for (int i = 0; i < DHTparametersCount; i++) {
|
|
|
|
createDiscovery(DHTsensor[i][0],
|
|
DHTTOPIC, DHTsensor[i][1], (char*)getUniqueId(DHTsensor[i][1], DHTsensor[i][2]).c_str(),
|
|
will_Topic, DHTsensor[i][3], DHTsensor[i][4],
|
|
DHTsensor[i][5], DHTsensor[i][6], DHTsensor[i][7],
|
|
0, "", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
}
|
|
# endif
|
|
|
|
# ifdef ZsensorADC
|
|
Log.trace(F("ADCDiscovery" CR));
|
|
char* ADCsensor[8] = {"sensor", "adc", "", "", jsonAdc, "", "", ""};
|
|
|
|
|
|
|
|
createDiscovery(ADCsensor[0],
|
|
ADCTOPIC, ADCsensor[1], (char*)getUniqueId(ADCsensor[1], ADCsensor[2]).c_str(),
|
|
will_Topic, ADCsensor[3], ADCsensor[4],
|
|
ADCsensor[5], ADCsensor[6], ADCsensor[7],
|
|
0, "", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
# endif
|
|
|
|
# ifdef ZsensorBH1750
|
|
#define BH1750parametersCount 3
|
|
Log.trace(F("BH1750Discovery" CR));
|
|
char* BH1750sensor[BH1750parametersCount][8] = {
|
|
{"sensor", "lux", "BH1750", "illuminance", jsonLux, "", "", "lx"},
|
|
{"sensor", "ftCd", "BH1750", "", jsonFtcd, "", "", ""},
|
|
{"sensor", "wattsm2", "BH1750", "", jsonWm2, "", "", "wm²"}
|
|
|
|
};
|
|
|
|
for (int i = 0; i < BH1750parametersCount; i++) {
|
|
|
|
createDiscovery(BH1750sensor[i][0],
|
|
subjectBH1750toMQTT, BH1750sensor[i][1], (char*)getUniqueId(BH1750sensor[i][1], BH1750sensor[i][2]).c_str(),
|
|
will_Topic, BH1750sensor[i][3], BH1750sensor[i][4],
|
|
BH1750sensor[i][5], BH1750sensor[i][6], BH1750sensor[i][7],
|
|
0, "", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
}
|
|
# endif
|
|
|
|
# ifdef ZsensorTSL2561
|
|
#define TSL2561parametersCount 3
|
|
Log.trace(F("TSL2561Discovery" CR));
|
|
char* TSL2561sensor[TSL2561parametersCount][8] = {
|
|
{"sensor", "lux", "TSL2561", "illuminance", jsonLux, "", "", "lx"},
|
|
{"sensor", "ftcd", "TSL2561", "", jsonFtcd, "", "", ""},
|
|
{"sensor", "wattsm2", "TSL2561", "", jsonWm2, "", "", "wm²"}
|
|
|
|
};
|
|
|
|
for (int i = 0; i < TSL2561parametersCount; i++) {
|
|
|
|
createDiscovery(TSL2561sensor[i][0],
|
|
subjectTSL12561toMQTT, TSL2561sensor[i][1], (char*)getUniqueId(TSL2561sensor[i][1], TSL2561sensor[i][2]).c_str(),
|
|
will_Topic, TSL2561sensor[i][3], TSL2561sensor[i][4],
|
|
TSL2561sensor[i][5], TSL2561sensor[i][6], TSL2561sensor[i][7],
|
|
0, "", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
}
|
|
# endif
|
|
|
|
# ifdef ZsensorHCSR501
|
|
Log.trace(F("HCSR501Discovery" CR));
|
|
char* HCSR501sensor[8] = {"binary_sensor", "hcsr501", "", "", jsonPresence, "true", "false", ""};
|
|
|
|
|
|
|
|
createDiscovery(HCSR501sensor[0],
|
|
subjectHCSR501toMQTT, HCSR501sensor[1], (char*)getUniqueId(HCSR501sensor[1], HCSR501sensor[2]).c_str(),
|
|
will_Topic, HCSR501sensor[3], HCSR501sensor[4],
|
|
HCSR501sensor[5], HCSR501sensor[6], HCSR501sensor[7],
|
|
0, "", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
# endif
|
|
|
|
# ifdef ZsensorGPIOInput
|
|
Log.trace(F("GPIOInputDiscovery" CR));
|
|
char* GPIOInputsensor[8] = {"binary_sensor", "GPIOInput", "", "", jsonGpio, INPUT_GPIO_ON_VALUE, INPUT_GPIO_OFF_VALUE, ""};
|
|
|
|
|
|
|
|
createDiscovery(GPIOInputsensor[0],
|
|
subjectGPIOInputtoMQTT, GPIOInputsensor[1], (char*)getUniqueId(GPIOInputsensor[1], GPIOInputsensor[2]).c_str(),
|
|
will_Topic, GPIOInputsensor[3], GPIOInputsensor[4],
|
|
GPIOInputsensor[5], GPIOInputsensor[6], GPIOInputsensor[7],
|
|
0, "", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
# endif
|
|
|
|
# ifdef ZsensorINA226
|
|
#define INA226parametersCount 3
|
|
Log.trace(F("INA226Discovery" CR));
|
|
char* INA226sensor[INA226parametersCount][8] = {
|
|
{"sensor", "volt", "INA226", "", jsonVolt, "", "", "V"},
|
|
{"sensor", "current", "INA226", "", jsonCurrent, "", "", "A"},
|
|
{"sensor", "power", "INA226", "", jsonPower, "", "", "W"}
|
|
|
|
};
|
|
|
|
for (int i = 0; i < INA226parametersCount; i++) {
|
|
|
|
createDiscovery(INA226sensor[i][0],
|
|
subjectINA226toMQTT, INA226sensor[i][1], (char*)getUniqueId(INA226sensor[i][1], INA226sensor[i][2]).c_str(),
|
|
will_Topic, INA226sensor[i][3], INA226sensor[i][4],
|
|
INA226sensor[i][5], INA226sensor[i][6], INA226sensor[i][7],
|
|
0, "", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
}
|
|
# endif
|
|
|
|
# ifdef ZsensorDS1820
|
|
|
|
pubOneWire_HADiscovery();
|
|
# endif
|
|
|
|
# ifdef ZactuatorONOFF
|
|
Log.trace(F("actuatorONOFFDiscovery" CR));
|
|
char* actuatorONOFF[8] = {"switch", "actuatorONOFF", "", "", "", "{\"cmd\":1}", "{\"cmd\":0}", ""};
|
|
|
|
|
|
|
|
createDiscovery(actuatorONOFF[0],
|
|
subjectGTWONOFFtoMQTT, actuatorONOFF[1], (char*)getUniqueId(actuatorONOFF[1], actuatorONOFF[2]).c_str(),
|
|
will_Topic, actuatorONOFF[3], actuatorONOFF[4],
|
|
actuatorONOFF[5], actuatorONOFF[6], actuatorONOFF[7],
|
|
0, "", "", true, subjectMQTTtoONOFF,
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
# endif
|
|
|
|
# ifdef ZgatewayRF
|
|
|
|
Log.trace(F("gatewayRFDiscovery" CR));
|
|
char* gatewayRF[8] = {"sensor", "gatewayRF", "", "", jsonVal, "", "", ""};
|
|
|
|
|
|
|
|
createDiscovery(gatewayRF[0],
|
|
subjectRFtoMQTT, gatewayRF[1], (char*)getUniqueId(gatewayRF[1], gatewayRF[2]).c_str(),
|
|
will_Topic, gatewayRF[3], gatewayRF[4],
|
|
gatewayRF[5], gatewayRF[6], gatewayRF[7],
|
|
0, "", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
|
|
# endif
|
|
|
|
# ifdef ZgatewayRF2
|
|
|
|
Log.trace(F("gatewayRF2Discovery" CR));
|
|
char* gatewayRF2[8] = {"sensor", "gatewayRF2", "", "", jsonAddress, "", "", ""};
|
|
|
|
|
|
|
|
createDiscovery(gatewayRF2[0],
|
|
subjectRF2toMQTT, gatewayRF2[1], (char*)getUniqueId(gatewayRF2[1], gatewayRF2[2]).c_str(),
|
|
will_Topic, gatewayRF2[3], gatewayRF2[4],
|
|
gatewayRF2[5], gatewayRF2[6], gatewayRF2[7],
|
|
0, "", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
# endif
|
|
|
|
# ifdef ZgatewayRFM69
|
|
|
|
Log.trace(F("gatewayRFM69Discovery" CR));
|
|
char* gatewayRFM69[8] = {"sensor", "gatewayRFM69", "", "", jsonVal, "", "", ""};
|
|
|
|
|
|
|
|
createDiscovery(gatewayRFM69[0],
|
|
subjectRFM69toMQTT, gatewayRFM69[1], (char*)getUniqueId(gatewayRFM69[1], gatewayRFM69[2]).c_str(),
|
|
will_Topic, gatewayRFM69[3], gatewayRFM69[4],
|
|
gatewayRFM69[5], gatewayRFM69[6], gatewayRFM69[7],
|
|
0, "", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
# endif
|
|
|
|
# ifdef ZgatewayLORA
|
|
|
|
Log.trace(F("gatewayLORADiscovery" CR));
|
|
char* gatewayLORA[8] = {"sensor", "gatewayLORA", "", "", jsonMsg, "", "", ""};
|
|
|
|
|
|
|
|
createDiscovery(gatewayLORA[0],
|
|
subjectLORAtoMQTT, gatewayLORA[1], (char*)getUniqueId(gatewayLORA[1], gatewayLORA[2]).c_str(),
|
|
will_Topic, gatewayLORA[3], gatewayLORA[4],
|
|
gatewayLORA[5], gatewayLORA[6], gatewayLORA[7],
|
|
0, "", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
# endif
|
|
|
|
# ifdef ZgatewaySRFB
|
|
|
|
Log.trace(F("gatewaySRFBDiscovery" CR));
|
|
char* gatewaySRFB[8] = {"sensor", "gatewaySRFB", "", "", jsonVal, "", "", ""};
|
|
|
|
|
|
|
|
createDiscovery(gatewaySRFB[0],
|
|
subjectSRFBtoMQTT, gatewaySRFB[1], (char*)getUniqueId(gatewaySRFB[1], gatewaySRFB[2]).c_str(),
|
|
will_Topic, gatewaySRFB[3], gatewaySRFB[4],
|
|
gatewaySRFB[5], gatewaySRFB[6], gatewaySRFB[7],
|
|
0, "", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
# endif
|
|
|
|
# ifdef ZgatewayPilight
|
|
|
|
Log.trace(F("gatewayPilightDiscovery" CR));
|
|
char* gatewayPilight[8] = {"sensor", "gatewayPilight", "", "", jsonMsg, "", "", ""};
|
|
|
|
|
|
|
|
createDiscovery(gatewayPilight[0],
|
|
subjectPilighttoMQTT, gatewayPilight[1], (char*)getUniqueId(gatewayPilight[1], gatewayPilight[2]).c_str(),
|
|
will_Topic, gatewayPilight[3], gatewayPilight[4],
|
|
gatewayPilight[5], gatewayPilight[6], gatewayPilight[7],
|
|
0, "", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
# endif
|
|
|
|
# ifdef ZgatewayIR
|
|
|
|
Log.trace(F("gatewayIRDiscovery" CR));
|
|
char* gatewayIR[8] = {"sensor", "gatewayIR", "", "", jsonVal, "", "", ""};
|
|
|
|
|
|
|
|
createDiscovery(gatewayIR[0],
|
|
subjectIRtoMQTT, gatewayIR[1], (char*)getUniqueId(gatewayIR[1], gatewayIR[2]).c_str(),
|
|
will_Topic, gatewayIR[3], gatewayIR[4],
|
|
gatewayIR[5], gatewayIR[6], gatewayIR[7],
|
|
0, "", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
# endif
|
|
|
|
# ifdef Zgateway2G
|
|
|
|
Log.trace(F("gateway2GDiscovery" CR));
|
|
char* gateway2G[8] = {"sensor", "gateway2G", "", "", jsonMsg, "", "", ""};
|
|
|
|
|
|
|
|
createDiscovery(gateway2G[0],
|
|
subject2GtoMQTT, gateway2G[1], (char*)getUniqueId(gateway2G[1], gateway2G[2]).c_str(),
|
|
will_Topic, gateway2G[3], gateway2G[4],
|
|
gateway2G[5], gateway2G[6], gateway2G[7],
|
|
0, "", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
# endif
|
|
|
|
# ifdef ZgatewayBT
|
|
createDiscovery("sensor",
|
|
subjectSYStoMQTT, "BT: Interval between scans", (char*)getUniqueId("interval", "").c_str(),
|
|
"", "", "{{ value_json.interval }}",
|
|
"", "", "ms",
|
|
0,
|
|
"", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
createDiscovery("sensor",
|
|
subjectSYStoMQTT, "BT: Connnect every X scan(s)", (char*)getUniqueId("scanbcnct", "").c_str(),
|
|
"", "", "{{ value_json.scanbcnct }}",
|
|
"", "", "",
|
|
0,
|
|
"", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
createDiscovery("switch",
|
|
will_Topic, "BT: Force scan", (char*)getUniqueId("force_scan", "").c_str(),
|
|
will_Topic, "", "",
|
|
"{\"interval\":0}", "", "",
|
|
0,
|
|
Gateway_AnnouncementMsg, will_Message, true, subjectMQTTtoBTset,
|
|
"", "", "", "", false,
|
|
stateClassNone
|
|
);
|
|
createDiscovery("switch",
|
|
"", "BT: Publish only sensors", (char*)getUniqueId("only_sensors", "").c_str(),
|
|
"", "", "",
|
|
"{\"onlysensors\":true}", "{\"onlysensors\":false}", "",
|
|
0,
|
|
Gateway_AnnouncementMsg, will_Message, true, subjectMQTTtoBTset,
|
|
"", "", "", "", true,
|
|
stateClassNone
|
|
);
|
|
createDiscovery("switch",
|
|
"", "BT: Publish HASS presence", (char*)getUniqueId("hasspresence", "").c_str(),
|
|
"", "", "",
|
|
"{\"hasspresence\":true}", "{\"hasspresence\":false}", "",
|
|
0,
|
|
Gateway_AnnouncementMsg, will_Message, true, subjectMQTTtoBTset,
|
|
"", "", "", "", true,
|
|
stateClassNone
|
|
);
|
|
# ifdef ESP32
|
|
createDiscovery("switch",
|
|
"", "SYS: Low Power Mode command", (char*)getUniqueId("lowpowermode", "").c_str(),
|
|
"", "", "",
|
|
"{\"lowpowermode\":2}", "{\"lowpowermode\":0}", "",
|
|
0,
|
|
"", "", true, subjectMQTTtoBTset,
|
|
"", "", "", "", true,
|
|
stateClassNone
|
|
);
|
|
createDiscovery("switch",
|
|
"", "BT: Connect to devices", (char*)getUniqueId("bleconnect", "").c_str(),
|
|
"", "", "",
|
|
"{\"bleconnect\":true}", "{\"bleconnect\":false}", "",
|
|
0,
|
|
Gateway_AnnouncementMsg, will_Message, true, subjectMQTTtoBTset,
|
|
"", "", "", "", true,
|
|
stateClassNone
|
|
);
|
|
# endif
|
|
# endif
|
|
}
|
|
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorADC.ino"
|
|
# 29 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorADC.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZsensorADC
|
|
|
|
# if defined(ESP8266)
|
|
ADC_MODE(ADC_TOUT);
|
|
# endif
|
|
|
|
|
|
unsigned long timeadc = 0;
|
|
|
|
void setupADC() {
|
|
Log.notice(F("ADC_GPIO: %d" CR), ADC_GPIO);
|
|
}
|
|
|
|
void MeasureADC() {
|
|
if (millis() > (timeadc + TimeBetweenReadingADC)) {
|
|
# if defined(ESP8266)
|
|
yield();
|
|
# endif
|
|
timeadc = millis();
|
|
static int persistedadc;
|
|
int val = analogRead(ADC_GPIO);
|
|
if (isnan(val)) {
|
|
Log.error(F("Failed to read from ADC !" CR));
|
|
} else {
|
|
if (val >= persistedadc + ThresholdReadingADC || val <= persistedadc - ThresholdReadingADC) {
|
|
Log.trace(F("Creating ADC buffer" CR));
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject ADCdata = jsonBuffer.to<JsonObject>();
|
|
ADCdata["adc"] = (int)val;
|
|
# if defined(ADC_DIVIDER)
|
|
float volt = 0;
|
|
# if defined(ESP32)
|
|
|
|
volt = val * (3.3 / 4096.0);
|
|
# elif defined(ESP8266)
|
|
|
|
volt = val * (3.3 / 1024.0);
|
|
# else
|
|
|
|
volt = val * (5.0 / 1024.0);
|
|
# endif
|
|
volt *= ADC_DIVIDER;
|
|
|
|
val = (volt * 100);
|
|
volt = (float)val / 100.0;
|
|
ADCdata["volt"] = (float)volt;
|
|
# endif
|
|
pub(ADCTOPIC, ADCdata);
|
|
persistedadc = val;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorAHTx0.ino"
|
|
# 38 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorAHTx0.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZsensorAHTx0
|
|
# include <stdint.h>
|
|
|
|
# include "Adafruit_AHTX0.h"
|
|
# include "Wire.h"
|
|
# include "config_AHTx0.h"
|
|
|
|
|
|
unsigned long timeAHTx0 = 0;
|
|
|
|
|
|
Adafruit_AHTX0 ahtSensor;
|
|
|
|
void setupZsensorAHTx0() {
|
|
delay(10);
|
|
Log.notice(F("AHTx0 Initialized - begin()" CR));
|
|
|
|
# if defined(ESP32)
|
|
Wire.begin(AHT_I2C_SDA, AHT_I2C_SCL);
|
|
if (!ahtSensor.begin(&Wire)) {
|
|
Log.error(F("Failed to initialize AHTx0 sensor!" CR));
|
|
}
|
|
# else
|
|
if (!ahtSensor.begin()) {
|
|
Log.error(F("Failed to initialize AHTx0 sensor!" CR));
|
|
}
|
|
# endif
|
|
}
|
|
|
|
void MeasureAHTTempHum() {
|
|
if (millis() > (timeAHTx0 + TimeBetweenReadingAHTx0)) {
|
|
Log.trace(F("Read AHTx0 Sensor" CR));
|
|
|
|
timeAHTx0 = millis();
|
|
static float persisted_aht_tempc;
|
|
static float persisted_aht_hum;
|
|
|
|
sensors_event_t ahtTempC, ahtHum;
|
|
if (!ahtSensor.getEvent(&ahtHum, &ahtTempC))
|
|
{
|
|
Log.error(F("Failed to read from sensor AHTx0!" CR));
|
|
return;
|
|
}
|
|
|
|
|
|
if (isnan(ahtTempC.temperature) || isnan(ahtHum.relative_humidity)) {
|
|
Log.error(F("Failed to read from sensor AHTx0!" CR));
|
|
} else {
|
|
Log.notice(F("Creating AHTx0 buffer" CR));
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject AHTx0data = jsonBuffer.to<JsonObject>();
|
|
|
|
if (ahtTempC.temperature != persisted_aht_tempc || AHTx0_always) {
|
|
float ahtTempF = convertTemp_CtoF(ahtTempC.temperature);
|
|
AHTx0data["tempc"] = (float)ahtTempC.temperature;
|
|
AHTx0data["tempf"] = (float)ahtTempF;
|
|
} else {
|
|
Log.notice(F("Same Temp. Don't send it" CR));
|
|
}
|
|
|
|
|
|
if (ahtHum.relative_humidity != persisted_aht_hum || AHTx0_always) {
|
|
AHTx0data["hum"] = (float)ahtHum.relative_humidity;
|
|
} else {
|
|
Log.notice(F("Same Humidity. Don't send it" CR));
|
|
}
|
|
|
|
if (AHTx0data.size() > 0) {
|
|
pub(AHTTOPIC, AHTx0data);
|
|
}
|
|
}
|
|
persisted_aht_tempc = ahtTempC.temperature;
|
|
persisted_aht_hum = ahtHum.relative_humidity;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorBH1750.ino"
|
|
# 39 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorBH1750.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZsensorBH1750
|
|
# include "Wire.h"
|
|
# include "math.h"
|
|
|
|
void setupZsensorBH1750() {
|
|
Log.notice(F("Setup BH1750 on adress: %H" CR), BH1750_i2c_addr);
|
|
Wire.begin();
|
|
Wire.beginTransmission(BH1750_i2c_addr);
|
|
Wire.write(0x10);
|
|
Wire.endTransmission();
|
|
delay(300);
|
|
}
|
|
|
|
void MeasureLightIntensity() {
|
|
if (millis() > (timebh1750 + TimeBetweenReadingBH1750)) {
|
|
Log.trace(F("Creating BH1750 buffer" CR));
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject BH1750data = jsonBuffer.to<JsonObject>();
|
|
|
|
timebh1750 = millis();
|
|
unsigned int i = 0;
|
|
static float persistedll;
|
|
static float persistedlf;
|
|
static float persistedlw;
|
|
unsigned int Lux;
|
|
float ftcd;
|
|
float Wattsm2;
|
|
|
|
|
|
Wire.requestFrom(BH1750_i2c_addr, 2);
|
|
if (Wire.available() != 2) {
|
|
Log.error(F("Failed to read from LightSensor BH1750!" CR));
|
|
} else {
|
|
i = Wire.read();
|
|
i <<= 8;
|
|
i |= Wire.read();
|
|
|
|
|
|
Lux = i / 1.2;
|
|
ftcd = Lux / 10.764;
|
|
Wattsm2 = Lux / 683.0;
|
|
|
|
|
|
if (Lux != persistedll || bh1750_always) {
|
|
BH1750data["lux"] = (unsigned int)Lux;
|
|
} else {
|
|
Log.trace(F("Same lux don't send it" CR));
|
|
}
|
|
|
|
|
|
if (ftcd != persistedlf || bh1750_always) {
|
|
BH1750data["ftcd"] = (unsigned int)ftcd;
|
|
} else {
|
|
Log.trace(F("Same ftcd don't send it" CR));
|
|
}
|
|
|
|
|
|
if (Wattsm2 != persistedlw || bh1750_always) {
|
|
BH1750data["wattsm2"] = (unsigned int)Wattsm2;
|
|
} else {
|
|
Log.trace(F("Same wattsm2 don't send it" CR));
|
|
}
|
|
if (BH1750data.size() > 0)
|
|
pub(subjectBH1750toMQTT, BH1750data);
|
|
}
|
|
persistedll = Lux;
|
|
persistedlf = ftcd;
|
|
persistedlw = Wattsm2;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorBME280.ino"
|
|
# 40 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorBME280.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZsensorBME280
|
|
# include <stdint.h>
|
|
|
|
# include "SparkFunBME280.h"
|
|
# include "Wire.h"
|
|
|
|
|
|
BME280 mySensor;
|
|
|
|
void setupZsensorBME280() {
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
|
|
Wire.begin(BME280_PIN_SDA, BME280_PIN_SCL);
|
|
# else
|
|
Wire.begin();
|
|
# endif
|
|
|
|
mySensor.settings.commInterface = I2C_MODE;
|
|
mySensor.settings.I2CAddress = BME280_i2c_addr;
|
|
Log.notice(F("Setup BME280 on adress: %X" CR), BME280_i2c_addr);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mySensor.settings.runMode = 3;
|
|
# 81 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorBME280.ino"
|
|
mySensor.settings.tStandby = 1;
|
|
# 90 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorBME280.ino"
|
|
mySensor.settings.filter = 4;
|
|
|
|
|
|
|
|
|
|
|
|
mySensor.settings.tempOverSample = 1;
|
|
|
|
|
|
|
|
|
|
|
|
mySensor.settings.pressOverSample = 1;
|
|
|
|
|
|
|
|
|
|
|
|
mySensor.settings.humidOverSample = 1;
|
|
|
|
|
|
|
|
|
|
|
|
mySensor.settings.tempCorrection = BME280Correction;
|
|
|
|
delay(10);
|
|
|
|
int ret = mySensor.begin();
|
|
if (ret == 0x60) {
|
|
Log.notice(F("Bosch BME280 successfully initialized: %X" CR), ret);
|
|
} else {
|
|
Log.notice(F("Bosch BME280 failed: %X" CR), ret);
|
|
}
|
|
}
|
|
|
|
void MeasureTempHumAndPressure() {
|
|
if (millis() > (timebme280 + TimeBetweenReadingbme280)) {
|
|
timebme280 = millis();
|
|
static float persisted_bme_tempc;
|
|
static float persisted_bme_tempf;
|
|
static float persisted_bme_hum;
|
|
static float persisted_bme_pa;
|
|
static float persisted_bme_altim;
|
|
static float persisted_bme_altift;
|
|
|
|
float BmeTempC = mySensor.readTempC();
|
|
float BmeTempF = mySensor.readTempF();
|
|
float BmeHum = mySensor.readFloatHumidity();
|
|
float BmePa = mySensor.readFloatPressure();
|
|
float BmeAltiM = mySensor.readFloatAltitudeMeters();
|
|
float BmeAltiFt = mySensor.readFloatAltitudeFeet();
|
|
|
|
|
|
if (isnan(BmeTempC) || isnan(BmeTempF) || isnan(BmeHum) || isnan(BmePa) || isnan(BmeAltiM) || isnan(BmeAltiFt)) {
|
|
Log.error(F("Failed to read from BME280!" CR));
|
|
} else {
|
|
Log.trace(F("Creating BME280 buffer" CR));
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject BME280data = jsonBuffer.to<JsonObject>();
|
|
|
|
if (BmeTempC != persisted_bme_tempc || bme280_always) {
|
|
BME280data["tempc"] = (float)BmeTempC;
|
|
} else {
|
|
Log.trace(F("Same Degrees C don't send it" CR));
|
|
}
|
|
|
|
|
|
if (BmeTempF != persisted_bme_tempf || bme280_always) {
|
|
BME280data["tempf"] = (float)BmeTempF;
|
|
} else {
|
|
Log.trace(F("Same Degrees F don't send it" CR));
|
|
}
|
|
|
|
|
|
if (BmeHum != persisted_bme_hum || bme280_always) {
|
|
BME280data["hum"] = (float)BmeHum;
|
|
} else {
|
|
Log.trace(F("Same Humidity don't send it" CR));
|
|
}
|
|
|
|
|
|
if (BmePa != persisted_bme_pa || bme280_always) {
|
|
BME280data["pa"] = (float)BmePa;
|
|
} else {
|
|
Log.trace(F("Same Pressure don't send it" CR));
|
|
}
|
|
|
|
|
|
if (BmeAltiM != persisted_bme_altim || bme280_always) {
|
|
Log.trace(F("Sending Altitude Meter to MQTT" CR));
|
|
BME280data["altim"] = (float)BmeAltiM;
|
|
} else {
|
|
Log.trace(F("Same Altitude Meter don't send it" CR));
|
|
}
|
|
|
|
|
|
if (BmeAltiFt != persisted_bme_altift || bme280_always) {
|
|
BME280data["altift"] = (float)BmeAltiFt;
|
|
} else {
|
|
Log.trace(F("Same Altitude Feet don't send it" CR));
|
|
}
|
|
if (BME280data.size() > 0)
|
|
pub(BMETOPIC, BME280data);
|
|
}
|
|
|
|
persisted_bme_tempc = BmeTempC;
|
|
persisted_bme_tempf = BmeTempF;
|
|
persisted_bme_hum = BmeHum;
|
|
persisted_bme_pa = BmePa;
|
|
persisted_bme_altim = BmeAltiM;
|
|
persisted_bme_altift = BmeAltiFt;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorDHT.ino"
|
|
# 30 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorDHT.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZsensorDHT
|
|
# include <DHT.h>
|
|
# include <DHT_U.h>
|
|
|
|
DHT dht(DHT_RECEIVER_GPIO, DHT_SENSOR_TYPE);
|
|
|
|
|
|
unsigned long timedht = 0;
|
|
|
|
void setupDHT() {
|
|
Log.notice(F("Reading DHT on pin: %d" CR), DHT_RECEIVER_GPIO);
|
|
}
|
|
|
|
void MeasureTempAndHum() {
|
|
if (millis() > (timedht + TimeBetweenReadingDHT)) {
|
|
timedht = millis();
|
|
static float persistedh;
|
|
static float persistedt;
|
|
float h = dht.readHumidity();
|
|
|
|
float t = dht.readTemperature();
|
|
|
|
if (isnan(h) || isnan(t)) {
|
|
Log.error(F("Failed to read from DHT sensor!" CR));
|
|
} else {
|
|
Log.trace(F("Creating DHT buffer" CR));
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject DHTdata = jsonBuffer.to<JsonObject>();
|
|
if (h != persistedh || dht_always) {
|
|
DHTdata["hum"] = (float)h;
|
|
} else {
|
|
Log.trace(F("Same hum don't send it" CR));
|
|
}
|
|
if (t != persistedt || dht_always) {
|
|
DHTdata["tempc"] = (float)t;
|
|
DHTdata["tempf"] = dht.convertCtoF(t);
|
|
} else {
|
|
Log.trace(F("Same temp don't send it" CR));
|
|
}
|
|
if (DHTdata.size() > 0)
|
|
pub(DHTTOPIC, DHTdata);
|
|
}
|
|
persistedh = h;
|
|
persistedt = t;
|
|
}
|
|
}
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorDS1820.ino"
|
|
# 26 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorDS1820.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZsensorDS1820
|
|
# include <DallasTemperature.h>
|
|
# include <OneWire.h>
|
|
|
|
OneWire owbus(DS1820_OWBUS_GPIO);
|
|
DallasTemperature ds1820(&owbus);
|
|
DeviceAddress ds1820_address, ds1820_devices[OW_MAX_SENSORS];
|
|
|
|
static uint8_t ds1820_count = 0;
|
|
static uint8_t ds1820_resolution[OW_MAX_SENSORS];
|
|
static String ds1820_type[OW_MAX_SENSORS];
|
|
static String ds1820_addr[OW_MAX_SENSORS];
|
|
|
|
void setupZsensorDS1820() {
|
|
Log.trace(F("DS1820: configured pin: %d for 1-wire bus" CR), DS1820_OWBUS_GPIO);
|
|
ds1820.begin();
|
|
|
|
|
|
uint8_t numDevicesOnBus = ds1820.getDeviceCount();
|
|
|
|
|
|
Log.notice(F("DS1820: Found %d devices" CR), numDevicesOnBus);
|
|
|
|
|
|
for (int deviceIndex = 0; deviceIndex < numDevicesOnBus && ds1820_count < OW_MAX_SENSORS; deviceIndex++) {
|
|
|
|
if (ds1820.getAddress(ds1820_address, deviceIndex) && ds1820.validFamily(ds1820_address)) {
|
|
ds1820_addr[ds1820_count] = String("0x");
|
|
for (uint8_t i = 0; i < 8; i++) {
|
|
if (ds1820_address[i] < 0x10) ds1820_addr[ds1820_count] += String("0");
|
|
ds1820_devices[ds1820_count][i] = ds1820_address[i];
|
|
ds1820_addr[ds1820_count] += String(ds1820_address[i], HEX);
|
|
}
|
|
|
|
|
|
if (ds1820_address[0] == 0x10) {
|
|
|
|
|
|
|
|
|
|
|
|
ds1820_type[ds1820_count] = String("DS1820/DS18S20");
|
|
} else if (ds1820_address[0] == 0x28) {
|
|
|
|
ds1820_type[ds1820_count] = String("DS18B20");
|
|
ds1820.setResolution(ds1820_address, DS1820_RESOLUTION);
|
|
} else if (ds1820_address[0] == 0x22) {
|
|
ds1820_type[ds1820_count] = String("DS1822");
|
|
ds1820.setResolution(ds1820_address, DS1820_RESOLUTION);
|
|
} else {
|
|
ds1820_type[ds1820_count] = String("DS1825");
|
|
ds1820.setResolution(ds1820_address, DS1820_RESOLUTION);
|
|
}
|
|
ds1820_resolution[ds1820_count] = ds1820.getResolution(ds1820_address);
|
|
Log.trace(F("DS1820: Device %d, Type: %s, Address: %s, Resolution: %d" CR),
|
|
ds1820_count,
|
|
(char*)ds1820_type[ds1820_count].c_str(),
|
|
(char*)ds1820_addr[ds1820_count].c_str(),
|
|
ds1820_resolution[ds1820_count]);
|
|
ds1820_count++;
|
|
}
|
|
}
|
|
|
|
if (ds1820.getDS18Count() == 0) {
|
|
Log.error(F("DS1820: Failed to enumerate sensors on 1-wire bus. Check your GPIO assignment!" CR));
|
|
}
|
|
|
|
|
|
|
|
ds1820.setWaitForConversion(false);
|
|
}
|
|
|
|
void pubOneWire_HADiscovery() {
|
|
|
|
# ifdef ZmqttDiscovery
|
|
|
|
if (disc) {
|
|
for (int index = 0; index < ds1820_count; index++) {
|
|
createDiscovery("sensor",
|
|
(char*)(String(OW_TOPIC) + "/" + ds1820_addr[index]).c_str(),
|
|
(char*)("DS12B20_" + String(index + 1) + "_c").c_str(),
|
|
(char*)(ds1820_addr[index] + "_c").c_str(),
|
|
will_Topic,
|
|
"temperature",
|
|
jsonTempc,
|
|
"", "", "°C",
|
|
0, "", "", true, "",
|
|
"", "", "", "", false,
|
|
stateClassMeasurement
|
|
);
|
|
}
|
|
}
|
|
# endif
|
|
}
|
|
|
|
void MeasureDS1820Temp() {
|
|
static float persisted_temp[OW_MAX_SENSORS];
|
|
static unsigned long timeDS1820 = 0;
|
|
static boolean triggeredConversion = false;
|
|
float current_temp[OW_MAX_SENSORS];
|
|
|
|
|
|
|
|
if (!triggeredConversion && ((millis() - timeDS1820) > (DS1820_INTERVAL_SEC * 1000UL - DS1820_CONV_TIME))) {
|
|
Log.trace(F("DS1820: Trigger temperature conversion..." CR));
|
|
ds1820.requestTemperatures();
|
|
triggeredConversion = true;
|
|
} else if (triggeredConversion && ((millis() - timeDS1820) > DS1820_INTERVAL_SEC * 1000UL)) {
|
|
timeDS1820 = millis();
|
|
triggeredConversion = false;
|
|
|
|
if (ds1820_count < 1) {
|
|
Log.error(F("DS1820: Failed to identify any temperature sensors on 1-wire bus during setup!" CR));
|
|
} else {
|
|
Log.trace(F("DS1820: Reading temperature(s) from %d sensor(s)..." CR), ds1820_count);
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject DS1820data = jsonBuffer.to<JsonObject>();
|
|
|
|
for (uint8_t i = 0; i < ds1820_count; i++) {
|
|
current_temp[i] = round(ds1820.getTempC(ds1820_devices[i]) * 10) / 10.0;
|
|
if (current_temp[i] == -127) {
|
|
Log.error(F("DS1820: Device %s currently disconnected!" CR), (char*)ds1820_addr[i].c_str());
|
|
} else if (DS1820_ALWAYS || current_temp[i] != persisted_temp[i]) {
|
|
DS1820data["tempf"] = (float)DallasTemperature::toFahrenheit(current_temp[i]);
|
|
DS1820data["tempc"] = (float)current_temp[i];
|
|
|
|
if (DS1820_DETAILS) {
|
|
DS1820data["type"] = ds1820_type[i];
|
|
DS1820data["res"] = ds1820_resolution[i] + String("bit" CR);
|
|
DS1820data["addr"] = ds1820_addr[i];
|
|
}
|
|
pub((char*)(String(OW_TOPIC) + "/" + ds1820_addr[i]).c_str(), DS1820data);
|
|
delay(10);
|
|
} else {
|
|
Log.trace(F("DS1820: Temperature for device %s didn't change, don't publish it." CR), (char*)ds1820_addr[i].c_str());
|
|
}
|
|
persisted_temp[i] = current_temp[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorGPIOInput.ino"
|
|
# 29 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorGPIOInput.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZsensorGPIOInput
|
|
# if defined(TRIGGER_GPIO) && INPUT_GPIO == TRIGGER_GPIO
|
|
unsigned long resetTime = 0;
|
|
# endif
|
|
unsigned long lastDebounceTime = 0;
|
|
int InputState = 3;
|
|
int lastInputState = 3;
|
|
|
|
void setupGPIOInput() {
|
|
Log.notice(F("Reading GPIO at pin: %d" CR), INPUT_GPIO);
|
|
pinMode(INPUT_GPIO, INPUT_PULLUP);
|
|
}
|
|
|
|
void MeasureGPIOInput() {
|
|
int reading = digitalRead(INPUT_GPIO);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (reading != lastInputState) {
|
|
|
|
lastDebounceTime = millis();
|
|
}
|
|
|
|
if ((millis() - lastDebounceTime) > GPIOInputDebounceDelay) {
|
|
|
|
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
yield();
|
|
# endif
|
|
# if defined(TRIGGER_GPIO) && INPUT_GPIO == TRIGGER_GPIO
|
|
if (reading == LOW) {
|
|
if (resetTime == 0) {
|
|
resetTime = millis();
|
|
} else if ((millis() - resetTime) > 10000) {
|
|
Log.trace(F("Button Held" CR));
|
|
Log.notice(F("Erasing ESP Config, restarting" CR));
|
|
setup_wifimanager(true);
|
|
}
|
|
} else {
|
|
resetTime = 0;
|
|
}
|
|
# endif
|
|
|
|
if (reading != InputState) {
|
|
InputState = reading;
|
|
Log.trace(F("Creating GPIOInput buffer" CR));
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject GPIOdata = jsonBuffer.to<JsonObject>();
|
|
if (InputState == HIGH) {
|
|
GPIOdata["gpio"] = "HIGH";
|
|
}
|
|
if (InputState == LOW) {
|
|
GPIOdata["gpio"] = "LOW";
|
|
}
|
|
if (GPIOdata.size() > 0)
|
|
pub(subjectGPIOInputtoMQTT, GPIOdata);
|
|
|
|
# ifdef ZactuatorONOFF
|
|
if (InputState == ACTUATOR_BUTTON_TRIGGER_LEVEL) {
|
|
ActuatorButtonTrigger();
|
|
}
|
|
# endif
|
|
}
|
|
}
|
|
|
|
|
|
lastInputState = reading;
|
|
}
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorGPIOKeyCode.ino"
|
|
# 26 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorGPIOKeyCode.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZsensorGPIOKeyCode
|
|
|
|
int InputStateGPIOKeyCode = 0x0f;
|
|
int lastInputStateGPIOKeyCode = 0x0f;
|
|
int lastLatchStateGPIOKeyCode = 0;
|
|
|
|
void setupGPIOKeyCode() {
|
|
pinMode(GPIOKeyCode_LATCH_GPIO, INPUT_PULLUP);
|
|
pinMode(GPIOKeyCode_D0_GPIO, INPUT_PULLUP);
|
|
pinMode(GPIOKeyCode_D1_GPIO, INPUT_PULLUP);
|
|
pinMode(GPIOKeyCode_D2_GPIO, INPUT_PULLUP);
|
|
|
|
}
|
|
|
|
void MeasureGPIOKeyCode() {
|
|
int latch = digitalRead(GPIOKeyCode_LATCH_GPIO);
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
yield();
|
|
# endif
|
|
|
|
if (latch > 0 && lastLatchStateGPIOKeyCode != latch) {
|
|
int reading = digitalRead(GPIOKeyCode_D0_GPIO) | (digitalRead(GPIOKeyCode_D1_GPIO) << 1) | (digitalRead(GPIOKeyCode_D2_GPIO) << 2);
|
|
|
|
|
|
char hex[3];
|
|
|
|
InputStateGPIOKeyCode = reading;
|
|
sprintf(hex, "%02x", InputStateGPIOKeyCode);
|
|
hex[2] = 0;
|
|
Log.notice(F("GPIOKeyCode %H" CR), hex);
|
|
pub(subjectGPIOKeyCodetoMQTT, hex);
|
|
lastLatchStateGPIOKeyCode = latch;
|
|
}
|
|
|
|
if (latch != lastLatchStateGPIOKeyCode) {
|
|
lastLatchStateGPIOKeyCode = latch;
|
|
Log.notice(F("GPIOKeyCode latch %d" CR), latch);
|
|
if (latch == 0)
|
|
pub(subjectGPIOKeyCodeStatetoMQTT, "done");
|
|
}
|
|
|
|
|
|
lastInputStateGPIOKeyCode = InputStateGPIOKeyCode;
|
|
}
|
|
}
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorHCSR04.ino"
|
|
# 30 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorHCSR04.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZsensorHCSR04
|
|
|
|
unsigned long timeHCSR04 = 0;
|
|
|
|
void setupHCSR04() {
|
|
Log.notice(F("HCSR04 trigger pin: %d" CR), HCSR04_TRI_GPIO);
|
|
Log.notice(F("HCSR04 echo pin: %d" CR), HCSR04_ECH_GPIO);
|
|
pinMode(HCSR04_TRI_GPIO, OUTPUT);
|
|
pinMode(HCSR04_ECH_GPIO, INPUT);
|
|
}
|
|
|
|
void MeasureDistance() {
|
|
if (millis() > (timeHCSR04 + TimeBetweenReadingHCSR04)) {
|
|
timeHCSR04 = millis();
|
|
Log.trace(F("Creating HCSR04 buffer" CR));
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject HCSR04data = jsonBuffer.to<JsonObject>();
|
|
digitalWrite(HCSR04_TRI_GPIO, LOW);
|
|
delayMicroseconds(2);
|
|
digitalWrite(HCSR04_TRI_GPIO, HIGH);
|
|
delayMicroseconds(10);
|
|
digitalWrite(HCSR04_TRI_GPIO, LOW);
|
|
unsigned long duration = pulseIn(HCSR04_ECH_GPIO, HIGH);
|
|
if (isnan(duration)) {
|
|
Log.error(F("Failed to read from HC SR04 sensor!" CR));
|
|
} else {
|
|
static unsigned int distance = 99999;
|
|
unsigned int d = duration / 58.2;
|
|
HCSR04data["distance"] = (int)d;
|
|
if (d > distance) {
|
|
HCSR04data["direction"] = "away";
|
|
Log.trace(F("HC SR04 Distance changed" CR));
|
|
} else if (d < distance) {
|
|
HCSR04data["direction"] = "towards";
|
|
Log.trace(F("HC SR04 Distance changed" CR));
|
|
} else if (HCSR04_always) {
|
|
HCSR04data["direction"] = "static";
|
|
Log.trace(F("HC SR04 Distance hasn't changed" CR));
|
|
}
|
|
distance = d;
|
|
if (HCSR04data.size() > 0)
|
|
pub(subjectHCSR04, HCSR04data);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorHCSR501.ino"
|
|
# 29 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorHCSR501.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZsensorHCSR501
|
|
|
|
void setupHCSR501() {
|
|
Log.notice(F("HCSR501 pin: %d" CR), HCSR501_GPIO);
|
|
pinMode(HCSR501_GPIO, INPUT);
|
|
# ifdef HCSR501_LED_NOTIFY_GPIO
|
|
pinMode(HCSR501_LED_NOTIFY_GPIO, OUTPUT);
|
|
digitalWrite(HCSR501_LED_NOTIFY_GPIO, LOW);
|
|
# endif
|
|
}
|
|
|
|
void MeasureHCSR501() {
|
|
if (millis() > TimeBeforeStartHCSR501) {
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject HCSR501data = jsonBuffer.to<JsonObject>();
|
|
static int pirState = LOW;
|
|
int PresenceValue = digitalRead(HCSR501_GPIO);
|
|
# if defined(ESP8266) || defined(ESP32)
|
|
yield();
|
|
# endif
|
|
if (PresenceValue == HIGH) {
|
|
if (pirState == LOW) {
|
|
|
|
HCSR501data["presence"] = "true";
|
|
pirState = HIGH;
|
|
}
|
|
} else {
|
|
if (pirState == HIGH) {
|
|
|
|
HCSR501data["presence"] = "false";
|
|
pirState = LOW;
|
|
}
|
|
}
|
|
# ifdef HCSR501_LED_NOTIFY_GPIO
|
|
digitalWrite(HCSR501_LED_NOTIFY_GPIO, pirState == HCSR501_LED_ON);
|
|
# endif
|
|
if (HCSR501data.size() > 0)
|
|
pub(subjectHCSR501toMQTT, HCSR501data);
|
|
}
|
|
}
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorHTU21.ino"
|
|
# 38 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorHTU21.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZsensorHTU21
|
|
# include <stdint.h>
|
|
|
|
# include "SparkFunHTU21D.h"
|
|
# include "Wire.h"
|
|
# include "config_HTU21.h"
|
|
|
|
|
|
unsigned long timehtu21 = 0;
|
|
|
|
|
|
HTU21D htuSensor;
|
|
|
|
void setupZsensorHTU21() {
|
|
delay(10);
|
|
Log.notice(F("HTU21 Initialized - begin()" CR));
|
|
|
|
# if defined(ESP32)
|
|
Wire.begin(I2C_SDA, I2C_SCL);
|
|
htuSensor.begin(Wire);
|
|
# else
|
|
htuSensor.begin();
|
|
# endif
|
|
}
|
|
|
|
void MeasureTempHum() {
|
|
if (millis() > (timehtu21 + TimeBetweenReadinghtu21)) {
|
|
Log.trace(F("Read HTU21 Sensor" CR));
|
|
|
|
timehtu21 = millis();
|
|
static float persisted_htu_tempc;
|
|
static float persisted_htu_hum;
|
|
|
|
float HtuTempC = htuSensor.readTemperature();
|
|
float HtuHum = htuSensor.readHumidity();
|
|
|
|
if (HtuTempC >= 998 || HtuHum >= 998) {
|
|
Log.error(F("Failed to read from sensor HTU21!" CR));
|
|
return;
|
|
}
|
|
|
|
|
|
if (isnan(HtuTempC) || isnan(HtuHum)) {
|
|
Log.error(F("Failed to read from sensor HTU21!" CR));
|
|
} else {
|
|
Log.notice(F("Creating HTU21 buffer" CR));
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject HTU21data = jsonBuffer.to<JsonObject>();
|
|
|
|
if (HtuTempC != persisted_htu_tempc || htu21_always) {
|
|
float HtuTempF = (HtuTempC * 1.8) + 32;
|
|
HTU21data["tempc"] = (float)HtuTempC;
|
|
HTU21data["tempf"] = (float)HtuTempF;
|
|
} else {
|
|
Log.notice(F("Same Temp. Don't send it" CR));
|
|
}
|
|
|
|
|
|
if (HtuHum != persisted_htu_hum || htu21_always) {
|
|
HTU21data["hum"] = (float)HtuHum;
|
|
} else {
|
|
Log.notice(F("Same Humidity. Don't send it" CR));
|
|
}
|
|
|
|
if (HTU21data.size() > 0)
|
|
pub(HTUTOPIC, HTU21data);
|
|
}
|
|
persisted_htu_tempc = HtuTempC;
|
|
persisted_htu_hum = HtuHum;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorINA226.ino"
|
|
# 35 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorINA226.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZsensorINA226
|
|
# include <Wire.h>
|
|
|
|
float rShunt = 0.1;
|
|
const int INA226_ADDR = 0x40;
|
|
|
|
|
|
unsigned long timeINA226 = 0;
|
|
|
|
void setupINA226() {
|
|
Wire.begin();
|
|
|
|
writeRegister(0x00, 0x4427);
|
|
}
|
|
|
|
void MeasureINA226() {
|
|
if (millis() > (timeINA226 + TimeBetweenReadingINA226)) {
|
|
timeINA226 = millis();
|
|
Log.trace(F("Creating INA226 buffer" CR));
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject INA226data = jsonBuffer.to<JsonObject>();
|
|
|
|
Log.trace(F("Retrieving electrical data" CR));
|
|
|
|
float volt = readRegister(0x02) * 0.00125;
|
|
|
|
int shuntvolt = readRegister(0x01);
|
|
if (shuntvolt && 0x8000) {
|
|
shuntvolt = ~shuntvolt;
|
|
shuntvolt += 1;
|
|
shuntvolt *= -1;
|
|
}
|
|
float current = shuntvolt * 0.0000025 / rShunt;
|
|
float power = abs(volt * current);
|
|
|
|
char volt_c[7];
|
|
char current_c[7];
|
|
char power_c[7];
|
|
dtostrf(volt, 6, 3, volt_c);
|
|
dtostrf(current, 6, 3, current_c);
|
|
dtostrf(power, 6, 3, power_c);
|
|
INA226data["volt"] = (char*)volt_c;
|
|
INA226data["current"] = (char*)current_c;
|
|
INA226data["power"] = (char*)power_c;
|
|
pub(subjectINA226toMQTT, INA226data);
|
|
}
|
|
}
|
|
|
|
static void writeRegister(byte reg, word value) {
|
|
Wire.beginTransmission(INA226_ADDR);
|
|
Wire.write(reg);
|
|
Wire.write((value >> 8) & 0xFF);
|
|
Wire.write(value & 0xFF);
|
|
Wire.endTransmission();
|
|
}
|
|
|
|
static word readRegister(byte reg) {
|
|
word res = 0x0000;
|
|
Wire.beginTransmission(INA226_ADDR);
|
|
Wire.write(reg);
|
|
if (Wire.endTransmission() == 0) {
|
|
if (Wire.requestFrom(INA226_ADDR, 2) >= 2) {
|
|
res = Wire.read() * 256;
|
|
res += Wire.read();
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorSHTC3.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZsensorSHTC3
|
|
# include <SparkFun_SHTC3.h>
|
|
|
|
SHTC3 mySHTC3;
|
|
|
|
|
|
unsigned long timedht = 0;
|
|
void errorDecoder(SHTC3_Status_TypeDef message);
|
|
|
|
void errorDecoder(SHTC3_Status_TypeDef message)
|
|
{
|
|
switch (message) {
|
|
case SHTC3_Status_Nominal:
|
|
Log.notice("Nominal");
|
|
break;
|
|
case SHTC3_Status_Error:
|
|
Log.error("Error");
|
|
break;
|
|
case SHTC3_Status_CRC_Fail:
|
|
Log.error("CRC Fail");
|
|
break;
|
|
default:
|
|
Log.error("Unknown return code");
|
|
break;
|
|
}
|
|
}
|
|
|
|
void setupSHTC3() {
|
|
Wire.begin();
|
|
errorDecoder(mySHTC3.begin());
|
|
}
|
|
|
|
void MeasureTempAndHum() {
|
|
if (millis() > (timedht + TimeBetweenReadingSHTC3)) {
|
|
timedht = millis();
|
|
static float persistedh;
|
|
static float persistedt;
|
|
SHTC3_Status_TypeDef result = mySHTC3.update();
|
|
if (mySHTC3.lastStatus == SHTC3_Status_Nominal) {
|
|
|
|
float t = mySHTC3.toDegC();
|
|
float h = mySHTC3.toPercent();
|
|
|
|
if (isnan(h) || isnan(t)) {
|
|
Log.error(F("Failed to read from SHTC3 sensor!" CR));
|
|
} else {
|
|
Log.trace(F("Creating SHTC3 buffer" CR));
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject SHTC3data = jsonBuffer.to<JsonObject>();
|
|
if (h != persistedh || shtc3_always) {
|
|
SHTC3data["hum"] = (float)h;
|
|
} else {
|
|
Log.trace(F("Same hum don't send it" CR));
|
|
}
|
|
if (t != persistedt || shtc3_always) {
|
|
SHTC3data["tempc"] = (float)t;
|
|
SHTC3data["tempf"] = mySHTC3.toDegF();
|
|
} else {
|
|
Log.trace(F("Same temp don't send it" CR));
|
|
}
|
|
if (SHTC3data.size() > 0)
|
|
pub(SHTC3TOPIC, SHTC3data);
|
|
}
|
|
persistedh = h;
|
|
persistedt = t;
|
|
} else {
|
|
errorDecoder(mySHTC3.lastStatus);
|
|
Log.error(F("Failed to read from SHTC3 sensor!" CR));
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
# 1 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorTSL2561.ino"
|
|
# 40 "/Users/sgracey/Code/OpenMQTTGatewayProd/main/ZsensorTSL2561.ino"
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZsensorTSL2561
|
|
# include <Adafruit_Sensor.h>
|
|
# include <Adafruit_TSL2561_U.h>
|
|
|
|
# include "Wire.h"
|
|
# include "math.h"
|
|
|
|
Adafruit_TSL2561_Unified tsl = Adafruit_TSL2561_Unified(TSL2561_ADDR_FLOAT, 12345);
|
|
|
|
void displaySensorDetails(void) {
|
|
sensor_t sensor;
|
|
tsl.getSensor(&sensor);
|
|
Log.trace(F("------------------------------------" CR));
|
|
Log.trace(("Sensor: %s" CR), sensor.name);
|
|
Log.trace(("Driver Ver: %s" CR), sensor.version);
|
|
Log.trace(("Unique ID: %s" CR), sensor.sensor_id);
|
|
Log.trace(("Max Value: %s lux" CR), sensor.max_value);
|
|
Log.trace(("Min Value: %s lux" CR), sensor.min_value);
|
|
Log.trace(("Resolution: %s lux" CR), sensor.resolution);
|
|
Log.trace(F("------------------------------------" CR));
|
|
delay(500);
|
|
}
|
|
|
|
void setupZsensorTSL2561() {
|
|
Log.notice(F("Setup TSL2561 on adress: %H" CR), TSL2561_ADDR_FLOAT);
|
|
Wire.begin();
|
|
Wire.beginTransmission(TSL2561_ADDR_FLOAT);
|
|
|
|
if (!tsl.begin()) {
|
|
Log.error(F("No TSL2561 detected" CR));
|
|
}
|
|
|
|
|
|
|
|
|
|
tsl.enableAutoRange(true);
|
|
|
|
|
|
|
|
tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS);
|
|
|
|
Log.trace(F("TSL2561 Initialized. Printing detials now." CR));
|
|
displaySensorDetails();
|
|
}
|
|
|
|
void MeasureLightIntensityTSL2561() {
|
|
if (millis() > (timetsl2561 + TimeBetweenReadingtsl2561)) {
|
|
static uint32_t persisted_lux;
|
|
timetsl2561 = millis();
|
|
|
|
Log.trace(F("Creating TSL2561 buffer" CR));
|
|
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
|
JsonObject TSL2561data = jsonBuffer.to<JsonObject>();
|
|
|
|
sensors_event_t event;
|
|
tsl.getEvent(&event);
|
|
if (event.light)
|
|
|
|
{
|
|
if (persisted_lux != event.light || tsl2561_always) {
|
|
persisted_lux = event.light;
|
|
|
|
TSL2561data["lux"] = (float)event.light;
|
|
TSL2561data["ftcd"] = (float)(event.light) / 10.764;
|
|
TSL2561data["wattsm2"] = (float)(event.light) / 683.0;
|
|
|
|
pub(subjectTSL12561toMQTT, TSL2561data);
|
|
} else {
|
|
Log.trace(F("Same lux value, do not send" CR));
|
|
}
|
|
} else {
|
|
Log.error(F("Failed to read from TSL2561" CR));
|
|
}
|
|
}
|
|
}
|
|
#endif |