arendst / Tasmota

Alternative firmware for ESP8266 and ESP32 based devices with easy configuration using webUI, OTA updates, automation using timers or rules, expandability and entirely local control over MQTT, HTTP, Serial or KNX. Full documentation at
https://tasmota.github.io/docs
GNU General Public License v3.0
22.21k stars 4.81k forks source link

Cayenne/mydevices.com MQTT #864

Closed dragondaud closed 6 years ago

dragondaud commented 7 years ago

I was planning to do some testing using Cayenne/mydevices.com with some Sonoff modules, and discovered that Tasmota's MQTT configuration fields are hardcoded to a size of 33, and always chops off 4 characters of USERNAME, PASSWORD and CLIENTID, which are all always 36 characters long as generated by their software.

I am using the current github source, verified I could flash my module from the .bin using the web interface with the current version, and that worked fine. I modified settings.h where the char arrays are defined, after doing a quick check that the code was using sizeof() and not another hard coded value. I found an instance where it was using sizeof(mqtt_user) in a copy, so I recompiled, and tried to upload. The upload fails: Upload Failed Upload buffer miscompare

I'm going to look thru the code more, but thought I should report the issue, since Cayenne is a popular and free IoT platform that this fine code won't currently work with.

ulab commented 7 years ago

I had a similar problem today that I wanted to look into. The goal was to use an FQDN instead of an IP for the syslog host and I noticed that it got cut at 32 chars when entered in the web frontend.

dragondaud commented 7 years ago

According to the MQTT spec, username and such should allow 65535 characters (16bit). However, the DNS system only allows 250 characters for a FQDN. Limiting either to only 32 is very restraining.

arendst commented 7 years ago

LOL

I bet you want to use TLS too.

ulab commented 7 years ago

Now that you suggest that... ;)

Of course I understand the limitations, but would it be an option to inform the user instead of just cutting it off?

Or for the webservice a "maxlength" for the tags for example? You seem to be using "length" which is not defined according to the HTML standard?

arendst commented 7 years ago

Regarding string length; See the wiki.

dragondaud commented 7 years ago

I'm aware the length is coded to the inadequate limit of 32 characters. I don't see anything else in the wiki regarding this issues. Unless you'd like to point me to something I missed, it sounds like you just aren't interested in interoperability.

davidelang commented 7 years ago

it's not "not interestedin interoperability", it's "ram is very limited and 32 characters works for most people, making it larger would break other configs due to lack of ram, so this is the current compromise"

I know there was something on the wiki about this limit, but I don't remember where.

David Lang

patbeirne commented 7 years ago

The parameter string lengths are in the code and duplicated here:

https://github.com/arendst/Sonoff-Tasmota/wiki/MQTT-Overview

davidelang commented 7 years ago

37 character userids and passwords are a waste of time, this is not going to be the only software that doesn't like them being that long.

dragondaud commented 7 years ago

Using fixed length buffers is a waste of time and space from my point of view, but to each their own. I am not affiliated with mydevices.com, and was simply trying to test their service, which is wholly incompatible with your software.

petrfaitl commented 6 years ago

As I understand there is an imposed (soft) limit on length of ClientID of 23 chars, in the standards. Not sure if the same applies to username and password.

Whilst I'd love to be able to use Cayenne, I think that's where we should be putting some pressure.

stale[bot] commented 6 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] commented 6 years ago

This issue will be auto-closed because there hasn't been any activity for a few months. Feel free to open a new one if you still experience this problem.

eadin79 commented 5 years ago

find out a possibility ... on Tasmota 6.3.0 we have free_1D5 since version 5.12.0e 20 bytes.... can be reused to MQTT and also you can comment by "//" some sensors not used by you in # define to save more memory .... on cayenne page is clear: standard lenght of Cayenne MQTT settings (?) are 36 + 40 + 36 = 112 so if the total size not equal to 112 reset settings h

andtsin commented 5 years ago

find out a possibility ... on Tasmota 6.3.0 we have free_1D5 since version 5.12.0e 20 bytes.... can be reused to MQTT and also you can comment by "//" some sensors not used by you in # define to save more memory .... on cayenne page is clear: standard lenght of Cayenne MQTT settings (?) are 36 + 40 + 36 = 112 so if the total size not equal to 112 reset settings h

So what you have to do to increase the length of the characters? I increased it manually for username to 36, password to 40, and client to 36, but nothing changed.. Please tell me what to do

eadin79 commented 5 years ago

@andtsin unfortunately I discovered that Tasmota do not support specific MQTT Cayenne publishing methods.... do not any chance ... and I dislike to get deep in Tasmota to modified for Cayenne. I will upload a trial made from different sources which I test now for 7 days already.... I made it based on:

https://gist.github.com/erikpena/a01ace32f7bef4a5ec52 https://github.com/regi18/Sonoff-Blynk AND .... https://community.mydevices.com/t/sonoff-or-other-esp8266-device-with-cayenne-mqtt-ota-ap/6948

then I addapt Cayenne ....

THIS is example for TH10+AM2301+CAYENNE (it is a tryout for IteadSI7021 but not successfully) NOT FINALIZED , but working on that ... /* Heavily inspired by: https://github.com/idreamsi/SonoffBoilerplate and https://github.com/tzapu/WiFiManager Converted from Blynk to Cayenne by WJ4IoT Preparation:

//Cayenne Virtual channels definitions

define UpTime_Channel 37

define UpDays_Channel 36

define TimeNow_Channel 40

define check_DST_Channel 43

define TimeSunSet_Channel 38

define TimeSunRise_Channel 39

define SketchVersion_Channel 31

define Schedule_Channel 26

define Relay_Channel 0

define ButtonStatus_Channel 51

define ButtonPressTime_Channel 50

define WiFiRSSI_Channel 32

define Humidity_Channel 70

define Temperature_Channel 71

// WiFi OTA Access Point

include

include

include

include //https://github.com/tzapu/WiFiManager (install by Library manager) RTFM

// WiFi network & Cayenne authentication info.

include //https://github.com/myDevicesIoT/Cayenne-MQTT-ESP

// some Cayenne stuff for Wemos D1 R2 with MQTT

include

define CAYANNE_DEBUG

define CAYANNE_PRINT Serial

include

define EEPROM_SALT 12663

typedef struct { int salt = EEPROM_SALT; char MQTT_username[37] ; // MQTT username char MQTT_Password[41] ; // MQTT password char MQTT_ClientID[37] ; // MQTT Client ID } WMSettings; WMSettings settings;

//for (flickering) LED status

include

Ticker ticker;

//+++++++++++++++++++++++++++++++++++++ ADIN ++++++++++++++++++++++++++++++++++ //#include "Si7021.h" //#include //Si7021 si7021;

include "DHT.h"

//#define DHTTYPE DHT11 // DHT 11 //#define DHTTYPE DHT22 // DHT 22 (AM2302)

define DHTTYPE DHT21 // DHT 21 (AM2301)

// DAT: 15 needed as were running on ESP8266 and 3.3v auto seems to screw up DHT dht1(SONOFF_INPUT, DHTTYPE, 15); //modified for sonoff ready //DHT dht2(DHTPIN2, DHTTYPE, 15); //DHT dht3(DHTPIN3, DHTTYPE, 15); //DHT dht4(DHTPIN4, DHTTYPE, 15);

include // Download from https://github.com/jfturcot/SimpleTimer

// Timer SimpleTimer timer; //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

// Library to connnect to time-servers in NL https://github.com/SensorsIot/SNTPtime

include

SNTPtime NTPnl("nl.pool.ntp.org"); strDateTime dateTime; strDateTime dateTime_wo_DST; int check_DST;

//various variables static long startPress = 0; //used to determine how long fysical SonOff Button is pressed unsigned long lastMillis = 0; //used to delay the Cayenne loop unsigned long lastMillis2 = 0; //used2 to delay the Cayenne loop

const char AP_hostname = "SonOff_Config"; //SonOff device details const char AP_password = "0000"; //SonOff device details

int time_now = 0; //set time funtion float time_now_d, time_sunset_d, time_sunrise_d; //to display time without a colon only a point //int int_scheduling = 1; // actuator to activate internal sceduling //Define variables before setup for routine publishSystemUpTime() : int updays = 0; int updays_old = 0;

//gets called when WiFiManager enters configuration mode void configModeCallback (WiFiManager *myWiFiManager) { Serial.println("Entered config mode"); Serial.println(WiFi.softAPIP()); //if you used auto generated SSID, print it Serial.println(myWiFiManager->getConfigPortalSSID()); //entered config mode, make led toggle faster ticker.attach(0.2, tick); }

//callback notifying us of the need to save config bool shouldSaveConfig = false; //flag for saving data void saveConfigCallback () { Serial.println("Should save config"); shouldSaveConfig = true; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

void tick() { //flash SonOff led on/off int state = digitalRead(SONOFF_LED); // get the current state of GPIO1 pin digitalWrite(SONOFF_LED, !state); // set pin to the opposite state } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

void restart() { // likely not working (sytem will hang) see comments: https://github.com/esp8266/Arduino/issues/1622 // based upon a comment in https://github.com/esp8266/Arduino/issues/1722 // WiFi.forceSleepBegin(); wdt_reset(); ESP.restart(); while(1)wdt_reset(); // but not working ESP.reset(); } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

void reset() { //reset wifi credentials WiFi.disconnect(); delay(1000); //ESP.reset(); ESP.restart(); delay(5000); } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void toggle(){

int value = digitalRead(SONOFF_LED); digitalWrite(SONOFF_RELAY, value); ///O FI BINE ?????? delay(200); Sync_LEDs(); } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

void Sync_LEDs() { int value = digitalRead(SONOFF_RELAY); Cayenne.virtualWrite(Relay_Channel, value); digitalWrite(SONOFF_LED, !value ); } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

void PRESS_SONOFF_BUTTON() {

long duration = 0; // reset duration long StartPress = millis(); // required to calculate how long SonOff button is pressed Cayenne.virtualWrite(ButtonStatus_Channel, 0); //where ended?

do { duration = millis() - StartPress; //how long is the button pressed? } while( digitalRead(SONOFF_BUTTON) == LOW );

if ( digitalRead(SONOFF_BUTTON) == HIGH ){ // button released again if (duration < 1500) { Serial.println("short press - toggle relay"); Cayenne.virtualWrite(ButtonStatus_Channel, 1); //where ended? toggle(); } else if (duration < 7000) { Serial.println("medium press - reset"); Cayenne.virtualWrite(ButtonStatus_Channel, 2); //where ended? reset(); } else if (duration < 60000) { Serial.println("long press - reset settings"); Cayenne.virtualWrite(ButtonStatus_Channel, 3); //where ended? //restart(); //goes automatic in a restart? } } Cayenne.virtualWrite(ButtonPressTime_Channel, duration); //duration } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

void publishSystemUpTime(){ / //Define variables before setup for routine publishSystemUpTime(): int updays = 0; int updays_old = 0; /
//source: http://community.mydevices.com/t/system-uptime-millis-to-dd-hh-mm-code-optimization-question-esp8266/4434 long millisecs = millis(); int systemUpTimeDy = int((millisecs / (1000606024)) % 365); float uptime = int((millis() / (10006060)) % 24) + int((millis() / (100060)) % 60) / 100.0; if ( updays > updays_old + systemUpTimeDy ) { updays_old = updays_old + updays; } updays = updays_old + systemUpTimeDy;

Cayenne.virtualWrite(UpTime_Channel, uptime);
Cayenne.virtualWrite(UpDays_Channel, updays);

} //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

void Timeroutine() {

// first parameter: Time zone; second parameter: 1 for European summer time; 2 for US daylight saving time (not implemented yet)
dateTime = NTPnl.getTime(1.0, 1); // get time from internal clock
//NTPnl.printDateTime(dateTime);
time_now = (dateTime.hour+1) * 60 + dateTime.minute;           ///adaugat ora Romaniei Adin
time_now_d = (dateTime.hour+1) * 1.0 + ( dateTime.minute / 100.0);

} //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

void setup(){

Serial.begin(115200); //++++++++++++++++++++++++++++++++++++++++++++++ ADIN ++++++++++++++++++++++++ //si7021.begin(); //Firware version //Serial.print("Si7021 firmware version: "); //Serial.println(si7021.getFirmwareVersion(), HEX); pinMode(SONOFF_INPUT, INPUT_PULLUP); // Initialise all dht sensors dht1.begin(); //dht2.begin(); //dht3.begin(); //dht4.begin(); timer.setInterval(200L, transmitData); // Method to execute every 200ms //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //define pin modes pinMode(SONOFF_BUTTON, INPUT); //setup button pinMode(SONOFF_RELAY, OUTPUT); //setup relay pinMode(SONOFF_LED, OUTPUT); // start ticker with 0.5 because we start in AP mode and try to connect ticker.attach(0.5, tick);

WiFiManager wifiManager; //set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode wifiManager.setAPCallback(configModeCallback);

//custom params EEPROM.begin(512); EEPROM.get(0, settings); EEPROM.end();

Serial.println("EEPROM settings are : "); Serial.println(settings.MQTT_username); Serial.println(settings.MQTT_Password); Serial.println(settings.MQTT_ClientID);

WiFiManagerParameter custom_Cayenne_text("Cayenne config.
"); wifiManager.addParameter(&custom_Cayenne_text);

WiFiManagerParameter custom_Cayenne_Username("Cayenne-Username", "Cayenne Username", settings.MQTT_username, 37); wifiManager.addParameter(&custom_Cayenne_Username);

WiFiManagerParameter custom_Cayenne_Password("Cayenne-Password", "Cayenne Password", settings.MQTT_Password, 41); wifiManager.addParameter(&custom_Cayenne_Password);

WiFiManagerParameter custom_Cayenne_ClientID("Cayenne-ClientID", "Cayenne ClientID", settings.MQTT_ClientID, 37); wifiManager.addParameter(&custom_Cayenne_ClientID);

//set config save notify callback wifiManager.setSaveConfigCallback(saveConfigCallback);

if (!wifiManager.autoConnect(AP_hostname, AP_password)) { Serial.println("failed to connect and hit timeout"); //reset and try again, or maybe put it to deep sleep ESP.reset(); delay(1000); }

//save the custom parameters to FS if (shouldSaveConfig) { Serial.println("Saving config");

strcpy(settings.MQTT_username, custom_Cayenne_Username.getValue());
strcpy(settings.MQTT_Password, custom_Cayenne_Password.getValue());
strcpy(settings.MQTT_ClientID, custom_Cayenne_ClientID.getValue());

Serial.println(settings.MQTT_username);
Serial.println(settings.MQTT_Password);
Serial.println(settings.MQTT_ClientID);

EEPROM.begin(512);
EEPROM.put(0, settings);
EEPROM.end();

}

// standard lenght of Cayenne MQTT settings (?) are 36 + 40 + 36 = 112 so if the total size not equal to 112 reset (go into AP-mode) int sizeme = strlen(settings.MQTT_username) + strlen(settings.MQTT_Password) + strlen(settings.MQTT_ClientID); Serial.print("lenght setting MQTT strings : "); Serial.println(sizeme); if ( sizeme != 112) { reset(); } Serial.println(settings.MQTT_username); Serial.println(settings.MQTT_Password); Serial.println(settings.MQTT_ClientID); Serial.print("Connected to: "); Serial.print(WiFi.SSID()); Serial.print(", Signal: "); Serial.println(WiFi.RSSI()); delay(1000); //Cayenne.begin(settings.MQTT_username, settings.MQTT_Password, settings.MQTT_ClientID); // we are already logged to Wi-Fi so no need for ssid, wifiPassword Cayenne.begin(settings.MQTT_username, settings.MQTT_Password,settings.MQTT_ClientID); // we are already logged to Wi-Fi so no need for ssid, wifiPassword

//OTA "Over The Air" ArduinoOTA.onStart([]() { Serial.println("Start OTA"); }); ArduinoOTA.onEnd([]() { Serial.println("\nEnd"); }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); }); ArduinoOTA.onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); else if (error == OTA_END_ERROR) Serial.println("End Failed"); }); ArduinoOTA.setHostname(AP_hostname); ArduinoOTA.setPassword(AP_password); ArduinoOTA.begin();

//if you get here you have connected to the WiFi Serial.println("connected..."); ticker.detach();

// ++++++++++++++++++ ADIN _____ ticker.attach(0.5, tick); // ++++++++++++++++++++++++++++++

//set time, DST, sunset and sunrise Timeroutine(); //Time_DST_refresh(); //sunsetrise(); Cayenne.virtualWrite(TimeNow_Channel, time_now_d); //Cayenne.virtualWrite(check_DST_Channel, check_DST, "digital_sensor", "d"); //Cayenne.virtualWrite(TimeSunSet_Channel, time_sunset_d); //Cayenne.virtualWrite(TimeSunRise_Channel, time_sunrise_d); Sync_LEDs(); //synchronise based upon status relay LED Sonoff and Actuator
Cayenne.virtualWrite(SketchVersion_Channel, 0.51); //display version of this sketch

// Set internal scheduling to true //Serial.print("int_scheduling : " ); //Serial.println(int_scheduling); //Cayenne.virtualWrite(Schedule_Channel, int_scheduling);

Serial.println("done setup"); }

void loop(){

ArduinoOTA.handle(); //ota loop Cayenne.loop(); timer.run();

if (digitalRead(SONOFF_BUTTON) == LOW) { // button on SonOff is pressed PRESS_SONOFF_BUTTON(); }

//Publish data every 10 seconds (60000 milliseconds). Change this value to publish at a different interval. //if (millis() - lastMillis > 10000) { //publihs temp and humidity every 10 sec // lastMillis = millis(); //+++++++++++++++++++++++++++++++ADIN++++++++++++++++++++++++++++++ //float HM = si7021.measureHumidity(); //float TM = si7021.getTemperatureFromPreviousHumidityMeasurement();

  // Read temperature as Celsius (the default)                //ASA MERGE SI TRIMITE AM2301
 /* float HM = dht1.readHumidity();
  float TM = dht1.readTemperature();

  Serial.print("Humidity: ");                           
  Serial.print(HM);
  Serial.print("% - Temperature: ");
  Serial.print(TM);
  Serial.println("C");
  Cayenne.virtualWrite(Humidity_Channel, HM);
  Cayenne.virtualWrite(Temperature_Channel, TM);
 */
 //delay(100);

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

// } if (millis() - lastMillis2 > 60000){ //publish time after 60sec lastMillis2 = millis(); publishSystemUpTime(); //calculate and display system up time //Misc Cayenne.virtualWrite(WiFiRSSI_Channel, WiFi.RSSI()); //display signal WiFi connection Serial.println(WiFi.RSSI()); //source: https://diyprojects.io/portable-wifi-scanner-oled-display-esp8266-signal-strength-connection-test-server/#.Whacbjco-Uk

//refresh present time
Timeroutine();
Cayenne.virtualWrite(TimeNow_Channel, time_now_d);

} }

CAYENNE_IN(0) { toggle() ; } // toggle relay and sync leds CAYENNE_IN(1) { restart() ; } // do not use!! CAYENNE_IN(2) { reset() ; } // into AP modes //CAYENNE_IN(26) { digitalWrite(int_scheduling, getValue.asInt()); } // set internal scheduling

void transmitData() { float h = dht1.readHumidity(); float t = dht1.readTemperature(); Serial.print("Temperature: "); Serial.print(t); Serial.println("C"); Serial.print("Humidity: "); Serial.print(h); Serial.println("%"); Cayenne.virtualWrite(V4, h); Cayenne.virtualWrite(V5, t);

if (digitalRead(SONOFF_BUTTON) == LOW) { // button on SonOff is pressed PRESS_SONOFF_BUTTON(); }

}