Skip to content

Commit

Permalink
Merge pull request #2 from arendst/development
Browse files Browse the repository at this point in the history
update fork from arendst/tasmota
  • Loading branch information
mike2nl authored Sep 25, 2018
2 parents 3c947e4 + ec421e6 commit 37905a2
Show file tree
Hide file tree
Showing 30 changed files with 3,220 additions and 326 deletions.
4 changes: 4 additions & 0 deletions .github/ISSUE_TEMPLATE/Bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ about: Create a report to help us improve

---

**IMPORTANT NOTICE**
If you do not complete the template below it is likely that your issue will not be addressed. When providing information about your issue please be as extensive as possible so that it can be solved by as little as possible responses.

**Describe the bug**
_A clear and concise description of what the bug is._


_Also, make sure these boxes are checked [x] before submitting your issue - Thank you!_
- [ ] _Searched the problem in issues and in the wiki_
- [ ] _Hardware used_ :
- [ ] _Development/Compiler/Upload tools used_ :
- [ ] _Provide the output of command_``status 0`` :
```
STATUS 0 OUTPUT HERE
Expand Down
4 changes: 4 additions & 0 deletions .github/ISSUE_TEMPLATE/Custom.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ about: Users Troubleshooting Help

---

**IMPORTANT NOTICE**
If you do not complete the template below it is likely that your issue will not be addressed. When providing information about your issue please be as extensive as possible so that it can be solved by as little as possible responses.

Make sure these boxes are checked [x] before submitting your issue - Thank you!

- [ ] Searched the problem in issues (https://github.com/arendst/Sonoff-Tasmota/issues)
- [ ] Searched the problem in the wiki (https://github.com/arendst/Sonoff-Tasmota/wiki/Troubleshooting)
- [ ] Searched the problem in the forum (https://groups.google.com/d/forum/sonoffusers)
- [ ] Searched the problem in the chat (https://discord.gg/Ks2Kzd4)
- [ ] Development/Compiler/Upload tools used :
- [ ] Hardware used :
- [ ] Provide the output of command ``status 0`` :
```
Expand Down
34 changes: 32 additions & 2 deletions sonoff/_changelog.ino
Original file line number Diff line number Diff line change
@@ -1,10 +1,40 @@
/* 6.2.1.3 20180907
/* 6.2.1.7 20180925
* Remove restart after ntpserver change and force NTP re-sync (#3890)
* Release full Shelly2 support
* Released tools/decode-config.py by Norbert Richter to decode configuration data. See file for information
*
* 6.2.1.6 20180922
* Removed commands PowerCal, VoltageCal and CurrentCal as more functionality is provided by commands PowerSet, VoltageSet and CurrentSet
* Allow decimals as input to commands PowerSet, VoltageSet and CurrentSet
* Add support for PCA9685 12bit 16pin hardware PWM driver (#3866)
* Add power value below 5W to Sonoff Pow R2 and S31 (#3745)
* Add force_update to Home Assistant discovery (#3873)
* Fix rule trigger POWER1#STATE execution after restart and SetOption0 is 0 (#3856)
* Disable serial logging on Shelly2 as serial is being used by energy monitoring (#3878)
* Fix Shelly2 wrong FrequencySet calculation and add input range checks (#3882)
*
* 6.2.1.5 20180921
* Add authentication to HTTP web pages
* Add energy monitoring to Shelly2 (#2789)
* Rewrite TSL2561 driver to fix some issues (#3681)
*
* 6.2.1.4 20180916
* Add command SerialSend5 to send raw serial data like "A5074100545293"
* Update MCP230xx driver
* Update Czech translation
* Update MP3 driver (#3800)
* Add userid/password option to decode-status.py (#3796)
* Fix syslog when emulation is selected (#2109, #3784)
* Fix Pzem2 compilation error (#3766, #3767)
* Add uncalibrated energy monitoring to Shelly2 (#2789)
*
* 6.2.1.3 20180907
* Change web Configure Module GPIO drop down list order for better readability
* Fix showing Period Power in energy threshold messages
* Fix ButtonRetain to not use default topic for clearing retain messages (#3737)
* Add sleep to Nova Fitness SDS01X sensor (#2841, #3724, #3749)
* Add Analog input AD0 enabled to sonoff-sensors.bin (#3756, #3757)
* Add Support to Xiaomi-Phillips Bulbs
* Add Support for Xiaomi-Philips Bulbs (#3787)
*
* 6.2.1.2 20180906
* Fix KNX PA exception. Regression from 6.2.1 buffer overflow caused by subStr() (#3700, #3710)
Expand Down
14 changes: 9 additions & 5 deletions sonoff/i18n.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@
#define D_CMND_BLINKTIME "BlinkTime"
#define D_CMND_BLINKCOUNT "BlinkCount"
#define D_CMND_SENSOR "Sensor"
#define D_CMND_DRIVER "Driver"
#define D_CMND_SAVEDATA "SaveData"
#define D_CMND_SETOPTION "SetOption"
#define D_CMND_TEMPERATURE_RESOLUTION "TempRes"
Expand Down Expand Up @@ -286,12 +287,10 @@
#define D_CMND_CURRENTLOW "CurrentLow"
#define D_CMND_CURRENTHIGH "CurrentHigh"
#define D_CMND_ENERGYRESET "EnergyReset"
#define D_CMND_POWERCAL "PowerCal"
#define D_CMND_POWERSET "PowerSet"
#define D_CMND_VOLTAGECAL "VoltageCal"
#define D_CMND_VOLTAGESET "VoltageSet"
#define D_CMND_CURRENTCAL "CurrentCal"
#define D_CMND_CURRENTSET "CurrentSet"
#define D_CMND_FREQUENCYSET "FrequencySet"
#define D_CMND_MAXPOWER "MaxPower"
#define D_CMND_MAXPOWERHOLD "MaxPowerHold"
#define D_CMND_MAXPOWERWINDOW "MaxPowerWindow"
Expand Down Expand Up @@ -419,7 +418,8 @@ enum UnitNames {
UNIT_SECTORS,
UNIT_VOLT,
UNIT_WATT,
UNIT_WATTHOUR };
UNIT_WATTHOUR,
UNIT_HERTZ };
const char kUnitNames[] PROGMEM =
D_UNIT_AMPERE "|"
D_UNIT_HOUR "|"
Expand All @@ -439,7 +439,8 @@ const char kUnitNames[] PROGMEM =
D_UNIT_SECTORS "|"
D_UNIT_VOLT "|"
D_UNIT_WATT "|"
D_UNIT_WATTHOUR ;
D_UNIT_WATTHOUR "|"
D_UNIT_HERTZ ;

const char S_JSON_COMMAND_NVALUE_SPACE_UNIT[] PROGMEM = "{\"%s\":\"%d %s\"}";
const char S_JSON_COMMAND_LVALUE_SPACE_UNIT[] PROGMEM = "{\"%s\":\"%lu %s\"}";
Expand Down Expand Up @@ -467,6 +468,9 @@ const char S_JSON_COMMAND_INDEX_NVALUE_ACTIVE_NVALUE[] PROGMEM = "{\"%s%d\":\"%d
const char S_JSON_SENSOR_INDEX_NVALUE[] PROGMEM = "{\"" D_CMND_SENSOR "%d\":%d}";
const char S_JSON_SENSOR_INDEX_SVALUE[] PROGMEM = "{\"" D_CMND_SENSOR "%d\":\"%s\"}";

const char S_JSON_DRIVER_INDEX_NVALUE[] PROGMEM = "{\"" D_CMND_DRIVER "%d\":%d}";
const char S_JSON_DRIVER_INDEX_SVALUE[] PROGMEM = "{\"" D_CMND_DRIVER "%d\":\"%s\"}";

const char JSON_SNS_TEMP[] PROGMEM = "%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s}";
const char JSON_SNS_TEMPHUM[] PROGMEM = "%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_HUMIDITY "\":%s}";

Expand Down
4 changes: 2 additions & 2 deletions sonoff/language/cs-CZ.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@
#define D_FALSE "Nepravda"
#define D_FILE "Soubor"
#define D_FREE_MEMORY "Volná paměť"
#define D_FREQUENCY "Frequency"
#define D_FREQUENCY "Kmitočet"
#define D_GAS "Plyn"
#define D_GATEWAY "Výchozí brána"
#define D_GROUP "Skupina"
Expand Down Expand Up @@ -128,7 +128,7 @@
#define D_POWERUSAGE_APPARENT "Apparent Power"
#define D_POWERUSAGE_REACTIVE "Reactive Power"
#define D_PRESSURE "Tlak"
#define D_PRESSUREATSEALEVEL "Tlak na úrovni hladiny moře"
#define D_PRESSUREATSEALEVEL "Tlak na hladině moře"
#define D_PROGRAM_FLASH_SIZE "Velikost paměti flash"
#define D_PROGRAM_SIZE "Velikost programu"
#define D_PROJECT "Projekt"
Expand Down
32 changes: 18 additions & 14 deletions sonoff/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -322,9 +322,13 @@ struct SYSCFG {

uint16_t mcp230xx_int_timer; // 718

byte free_71A[180]; // 71A
byte free_71A[174]; // 71A

char mems[MAX_RULE_MEMS][10]; // 7CE
unsigned long energy_frequency_calibration; // 7C8

byte free_7CC[2]; // 7CC

char mems[MAX_RULE_MEMS][10]; // 7CE
// 800 Full - no more free locations

char rules[MAX_RULE_SETS][MAX_RULE_SIZE]; // 800 uses 512 bytes in v5.12.0m, 3 x 512 bytes in v5.14.0b
Expand All @@ -333,21 +337,21 @@ struct SYSCFG {
} Settings;

struct RTCRBT {
uint16_t valid; // 000
uint8_t fast_reboot_count; // 002
uint8_t free_003[1]; // 003
uint16_t valid; // 280 (RTC memory offset 100 - sizeof(RTCRBT))
uint8_t fast_reboot_count; // 282
uint8_t free_003[1]; // 283
} RtcReboot;

struct RTCMEM {
uint16_t valid; // 000
byte oswatch_blocked_loop; // 002
uint8_t ota_loader; // 003
unsigned long energy_kWhtoday; // 004
unsigned long energy_kWhtotal; // 008
unsigned long pulse_counter[MAX_COUNTERS]; // 00C
power_t power; // 01C
uint8_t free_020[60]; // 020
// 05C next free location (64 (=core) + 100 (=tasmota offset) + 92 (=0x5C RTCMEM struct) = 256 bytes (max = 512))
uint16_t valid; // 290 (RTC memory offset 100)
byte oswatch_blocked_loop; // 292
uint8_t ota_loader; // 293
unsigned long energy_kWhtoday; // 294
unsigned long energy_kWhtotal; // 298
unsigned long pulse_counter[MAX_COUNTERS]; // 29C
power_t power; // 2AC
uint8_t free_020[60]; // 2B0
// 2EC - 2FF free locations
} RtcSettings;

struct TIME_T {
Expand Down
4 changes: 2 additions & 2 deletions sonoff/settings.ino
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ void RtcSettingsSave()

void RtcSettingsLoad()
{
ESP.rtcUserMemoryRead(100, (uint32_t*)&RtcSettings, sizeof(RTCMEM));
ESP.rtcUserMemoryRead(100, (uint32_t*)&RtcSettings, sizeof(RTCMEM)); // 0x290
#ifdef DEBUG_THEO
AddLog_P(LOG_LEVEL_DEBUG, PSTR("Dump: Load"));
RtcSettingsDump();
Expand Down Expand Up @@ -145,7 +145,7 @@ void RtcRebootSave()

void RtcRebootLoad()
{
ESP.rtcUserMemoryRead(100 - sizeof(RTCRBT), (uint32_t*)&RtcReboot, sizeof(RTCRBT));
ESP.rtcUserMemoryRead(100 - sizeof(RTCRBT), (uint32_t*)&RtcReboot, sizeof(RTCRBT)); // 0x280
if (RtcReboot.valid != RTC_MEM_VALID) {
memset(&RtcReboot, 0, sizeof(RTCRBT));
RtcReboot.valid = RTC_MEM_VALID;
Expand Down
36 changes: 22 additions & 14 deletions sonoff/sonoff.ino
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ enum TasmotaCommands {
CMND_LOGHOST, CMND_LOGPORT, CMND_IPADDRESS, CMND_NTPSERVER, CMND_AP, CMND_SSID, CMND_PASSWORD, CMND_HOSTNAME,
CMND_WIFICONFIG, CMND_FRIENDLYNAME, CMND_SWITCHMODE,
CMND_TELEPERIOD, CMND_RESTART, CMND_RESET, CMND_TIMEZONE, CMND_TIMESTD, CMND_TIMEDST, CMND_ALTITUDE, CMND_LEDPOWER, CMND_LEDSTATE,
CMND_I2CSCAN, CMND_SERIALSEND, CMND_BAUDRATE, CMND_SERIALDELIMITER };
CMND_I2CSCAN, CMND_SERIALSEND, CMND_BAUDRATE, CMND_SERIALDELIMITER, CMND_DRIVER };
const char kTasmotaCommands[] PROGMEM =
D_CMND_BACKLOG "|" D_CMND_DELAY "|" D_CMND_POWER "|" D_CMND_FANSPEED "|" D_CMND_STATUS "|" D_CMND_STATE "|" D_CMND_POWERONSTATE "|" D_CMND_PULSETIME "|"
D_CMND_BLINKTIME "|" D_CMND_BLINKCOUNT "|" D_CMND_SENSOR "|" D_CMND_SAVEDATA "|" D_CMND_SETOPTION "|" D_CMND_TEMPERATURE_RESOLUTION "|" D_CMND_HUMIDITY_RESOLUTION "|"
Expand All @@ -93,7 +93,7 @@ const char kTasmotaCommands[] PROGMEM =
D_CMND_LOGHOST "|" D_CMND_LOGPORT "|" D_CMND_IPADDRESS "|" D_CMND_NTPSERVER "|" D_CMND_AP "|" D_CMND_SSID "|" D_CMND_PASSWORD "|" D_CMND_HOSTNAME "|"
D_CMND_WIFICONFIG "|" D_CMND_FRIENDLYNAME "|" D_CMND_SWITCHMODE "|"
D_CMND_TELEPERIOD "|" D_CMND_RESTART "|" D_CMND_RESET "|" D_CMND_TIMEZONE "|" D_CMND_TIMESTD "|" D_CMND_TIMEDST "|" D_CMND_ALTITUDE "|" D_CMND_LEDPOWER "|" D_CMND_LEDSTATE "|"
D_CMND_I2CSCAN "|" D_CMND_SERIALSEND "|" D_CMND_BAUDRATE "|" D_CMND_SERIALDELIMITER;
D_CMND_I2CSCAN "|" D_CMND_SERIALSEND "|" D_CMND_BAUDRATE "|" D_CMND_SERIALDELIMITER "|" D_CMND_DRIVER;

const uint8_t kIFan02Speed[4][3] = {{6,6,6}, {7,6,6}, {7,7,6}, {7,6,7}};

Expand Down Expand Up @@ -335,7 +335,8 @@ void SetDevicePower(power_t rpower, int source)
}
}

XdrvSetPower(rpower);
XdrvMailbox.index = rpower;
XdrvCall(FUNC_SET_POWER);

if ((SONOFF_DUAL == Settings.module) || (CH4 == Settings.module)) {
Serial.write(0xA0);
Expand Down Expand Up @@ -461,10 +462,11 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)

grpflg = (strstr(topicBuf, Settings.mqtt_grptopic) != NULL);
fallback_topic_flag = (strstr(topicBuf, mqtt_client) != NULL);
type = strrchr(topicBuf, '/') +1; // Last part of received topic is always the command (type)
type = strrchr(topicBuf, '/'); // Last part of received topic is always the command (type)

index = 1;
if (type != NULL) {
type++;
for (i = 0; i < strlen(type); i++) {
type[i] = toupper(type[i]);
}
Expand Down Expand Up @@ -679,16 +681,19 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, (Settings.save_data > 1) ? stemp1 : GetStateText(Settings.save_data));
}
else if (CMND_SENSOR == command_code) {
else if ((CMND_SENSOR == command_code) || (CMND_DRIVER == command_code)) {
XdrvMailbox.index = index;
XdrvMailbox.data_len = data_len;
XdrvMailbox.payload16 = payload16;
XdrvMailbox.payload = payload;
XdrvMailbox.grpflg = grpflg;
XdrvMailbox.topic = command;
XdrvMailbox.data = dataBuf;
XsnsCall(FUNC_COMMAND);
// if (!XsnsCall(FUNC_COMMAND)) type = NULL;
if (CMND_SENSOR == command_code) {
XsnsCall(FUNC_COMMAND);
} else {
XdrvCall(FUNC_COMMAND);
}
}
else if ((CMND_SETOPTION == command_code) && (index < 82)) {
byte ptype;
Expand Down Expand Up @@ -969,22 +974,25 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.baudrate * 1200);
}
else if ((CMND_SERIALSEND == command_code) && (index > 0) && (index <= 4)) {
else if ((CMND_SERIALSEND == command_code) && (index > 0) && (index <= 5)) {
SetSeriallog(LOG_LEVEL_NONE);
Settings.flag.mqtt_serial = 1;
Settings.flag.mqtt_serial_raw = (4 == index) ? 1 : 0;
Settings.flag.mqtt_serial_raw = (index > 3) ? 1 : 0;
if (data_len > 0) {
if (1 == index) {
Serial.printf("%s\n", dataBuf);
Serial.printf("%s\n", dataBuf); // "Hello Tiger\n"
}
else if (2 == index || 4 == index) {
for (int i = 0; i < data_len; i++) {
Serial.write(dataBuf[i]);
Serial.write(dataBuf[i]); // "Hello Tiger" or "A0"
}
}
else if (3 == index) {
uint16_t dat_len = data_len;
Serial.printf("%s", Unescape(dataBuf, &dat_len));
Serial.printf("%s", Unescape(dataBuf, &dat_len)); // "Hello\f"
}
else if (5 == index) {
SerialSendRaw(dataBuf, data_len); // "AA004566"
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
}
Expand Down Expand Up @@ -1035,7 +1043,8 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
for (i = 0; i < strlen(Settings.ntp_server[index -1]); i++) {
if (Settings.ntp_server[index -1][i] == ',') Settings.ntp_server[index -1][i] = '.';
}
restart_flag = 2;
// restart_flag = 2; // Issue #3890
ntp_force_sync = 1;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.ntp_server[index -1]);
}
Expand Down Expand Up @@ -2606,7 +2615,6 @@ void setup()
SetPulseTimer(i, Settings.pulse_timer[i]);
}
}

blink_powersave = power;

snprintf_P(log_data, sizeof(log_data), PSTR(D_PROJECT " %s %s (" D_CMND_TOPIC " %s, " D_FALLBACK " %s, " D_CMND_GROUPTOPIC " %s) " D_VERSION " %s-" ARDUINO_ESP8266_RELEASE),
Expand Down
2 changes: 1 addition & 1 deletion sonoff/sonoff_version.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#ifndef _SONOFF_VERSION_H_
#define _SONOFF_VERSION_H_

#define VERSION 0x06020103
#define VERSION 0x06020107

#define D_PROGRAMNAME "Sonoff-Tasmota"
#define D_AUTHOR "Theo Arends"
Expand Down
15 changes: 15 additions & 0 deletions sonoff/support.ino
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,21 @@ void ClaimSerial()
Settings.baudrate = baudrate / 1200;
}

void SerialSendRaw(char *codes, int size)
{
char *p;
char stemp[3];
uint8_t code;

while (size > 0) {
snprintf(stemp, sizeof(stemp), codes);
code = strtol(stemp, &p, 16);
Serial.write(code);
size -= 2;
codes += 2;
}
}

uint32_t GetHash(const char *buffer, size_t size)
{
uint32_t hash = 0;
Expand Down
8 changes: 6 additions & 2 deletions sonoff/user_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,9 +294,12 @@
// #define USE_SI1145 // Enable SI1145/46/47 sensor (I2C address 0x60) (+1k code)
#define USE_LM75AD // Enable LM75AD sensor (I2C addresses 0x48 - 0x4F) (+0k5 code)
// #define USE_APDS9960 // Enable APDS9960 Proximity Sensor (I2C address 0x39). Disables SHT and VEML6070 (+4k7 code)
// #define USE_MCP230xx // Enable MCP23008/MCP23017 for GP INPUT ONLY (I2C addresses 0x20 - 0x27) providing command Sensor29 for configuration (+4k7 code)
// #define USE_MCP230xx // Enable MCP23008/MCP23017 - Must define I2C Address in #define USE_MCP230xx_ADDR below - range 0x20 - 0x27 (+4k7 code)
// #define USE_MCP230xx_ADDR 0x20 // Enable MCP23008/MCP23017 I2C Address to use (Must be within range 0x20 through 0x27 - set according to your wired setup)
// #define USE_MCP230xx_OUTPUT // Enable MCP23008/MCP23017 OUTPUT support through sensor29 commands (+1k5 code)
// #define USE_MCP230xx_DISPLAYOUTPUT // Enable MCP23008/MCP23017 to display state of OUTPUT pins on Web UI (+0k2 code)
// #define USE_PCA9685 // Enable PCA9685 I2C HW PWM Driver - Must define I2C Address in #define USE_PCA9685_ADDR below - range 0x40 - 0x47 (+1k4 code)
// #define USE_PCA9685_ADDR 0x40 // Enable PCA9685 I2C Address to use (Must be within range 0x40 through 0x47 - set according to your wired setup)
// #define USE_MPR121 // Enable MPR121 controller (I2C addresses 0x5A, 0x5B, 0x5C and 0x5D) in input mode for touch buttons (+1k3 code)
// #define USE_CCS811 // Enable CCS811 sensor (I2C address 0x5A) (+2k2 code)
// #define USE_MPU6050 // Enable MPU6050 sensor (I2C address 0x68 AD0 low or 0x69 AD0 high) (+2k6 code)
Expand Down Expand Up @@ -342,11 +345,12 @@
//#define USE_SDM630 // Add support for Eastron SDM630-Modbus energy meter (+2k code)
#define SDM630_SPEED 9600 // SDM630-Modbus RS485 serial speed (default: 9600 baud)
//#define USE_MP3_PLAYER // Use of the DFPlayer Mini MP3 Player RB-DFR-562 commands: play, volume and stop
// #define MP3_VOLUME 10 // Set the startup volume on init, the range can be 0..30(max)
#define MP3_VOLUME 10 // Set the startup volume on init, the range can be 0..30(max)

// Power monitoring sensors -----------------------
#define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code)
#define USE_PZEM2 // Add support for PZEM003,014,016,017 Energy monitor (+1k1 code)
#define USE_MCP39F501 // Add support for MCP39F501 Energy monitor as used in Shelly 2 (+3k1 code)

// -- Low level interface devices -----------------
#define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+4k code, 0k3 mem, 48 iram)
Expand Down
Loading

0 comments on commit 37905a2

Please sign in to comment.