diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino index 197a0a140..31ad23fcc 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,5 +1,5 @@ /* 6.0.0b - * Add initial support for Sonoff iFan02 - Module 44 - Command FanSpeed 0..3 - Webpage will only allow Toggle1 (#2839) + * Add support for Sonoff iFan02 as module 44 introducing command FanSpeed 0..3 (#2839) * Add support for Sonoff S26 Smart Socket (#2808) * Add command SetOption30 to enforce Hass discovery as light group (#1784) * Add decimal values support for commands ADD, SUB, MULT and SCALE (#3083, #3089) diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 6cd62ec56..12a6a35a2 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -96,9 +96,7 @@ const char kTasmotaCommands[] PROGMEM = 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; -//const uint8_t kIFan02Speed[4][3] = {{0,0,0}, {1,0,0}, {1,1,0}, {1,0,1}}; const uint8_t kIFan02Speed[4][3] = {{6,6,6}, {7,6,6}, {7,7,6}, {7,6,7}}; -//const uint8_t kIFan02Speed[4][3] = {{16,16,16}, {17,16,16}, {17,17,16}, {17,16,17}}; // Global variables unsigned long feature_drv1; // Compiled driver feature map @@ -363,6 +361,23 @@ void SetLedPower(uint8_t state) digitalWrite(pin[GPIO_LED1], (bitRead(led_inverted, 0)) ? !state : state); } +uint8_t GetFanspeed() +{ + uint8_t fanspeed = 0; + +// if (SONOFF_IFAN02 == Settings.module) { + /* Fanspeed is controlled by relay 2, 3 and 4 as in Sonoff 4CH. + 000x = 0 + 001x = 1 + 011x = 2 + 101x = 3 + */ + fanspeed = (uint8_t)(power &0xF) >> 1; + if (fanspeed) { fanspeed = (fanspeed >> 1) +1; } +// } + return fanspeed; +} + /********************************************************************************************/ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) @@ -507,17 +522,14 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) return; } else if ((CMND_FANSPEED == command_code) && (SONOFF_IFAN02 == Settings.module)) { - uint8_t fanspeed = (uint8_t)(power &0xF) >> 1; - if (fanspeed) { fanspeed = (fanspeed >> 1) +1; } - if ((payload >= 0) && (payload <= 3) && (payload != fanspeed)) { - fanspeed = payload; + if ((payload >= 0) && (payload <= 3) && (payload != GetFanspeed())) { for (byte i = 0; i < 3; i++) { - uint8_t state = kIFan02Speed[fanspeed][i]; -// uint8_t state = pgm_read_byte(kIFan02Speed +(fanspeed *3) +i); - ExecuteCommandPower(i +2, state, SRC_IGNORE); + uint8_t state = kIFan02Speed[payload][i]; +// uint8_t state = pgm_read_byte(kIFan02Speed +(payload *3) +i); + ExecuteCommandPower(i +2, state, SRC_IGNORE); // Use relay 2, 3 and 4 } } - snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, fanspeed); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, GetFanspeed()); } else if (CMND_STATUS == command_code) { if ((payload < 0) || (payload > MAX_STATUS)) payload = 99; @@ -1207,20 +1219,14 @@ void ExecuteCommandPower(byte device, byte state, int source) // ShowSource(source); -/* if (SONOFF_IFAN02 == Settings.module) { - if (state > 15) { // Only allow Fanspeed control over relay 2..4 - state -= 10; - blink_mask &= 1; - Settings.flag.interlock = 0; - Settings.pulse_timer[1] = 0; - Settings.pulse_timer[2] = 0; - Settings.pulse_timer[3] = 0; - } else { - device = 1; // Only allow user control over light - } + blink_mask &= 1; // No blinking on the fan relays + Settings.flag.interlock = 0; // No interlock mode as it is already done by the microcontroller + Settings.pulse_timer[1] = 0; // No pulsetimers on the fan relays + Settings.pulse_timer[2] = 0; + Settings.pulse_timer[3] = 0; } -*/ + uint8_t publish_power = 1; if ((POWER_OFF_NO_STATE == state) || (POWER_ON_NO_STATE == state)) { state &= 1; @@ -1447,6 +1453,10 @@ void MqttShowState() LightState(1); } else { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":\"%s\""), mqtt_data, GetPowerDevice(stemp1, i +1, sizeof(stemp1), Settings.flag.device_index_enable), GetStateText(bitRead(power, i))); + if (SONOFF_IFAN02 == Settings.module) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_CMND_FANSPEED "\":%d"), mqtt_data, GetFanspeed()); + break; + } } } @@ -1521,6 +1531,7 @@ void PerformEverySecond() if (!status_update_timer) { for (byte i = 1; i <= devices_present; i++) { MqttPublishPowerState(i); + if (SONOFF_IFAN02 == Settings.module) { break; } // Only report status of light relay } } } diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 85cdd7044..dd061cae6 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -838,20 +838,20 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, 0, 0, 0 }, { "Sonoff iFan02", // Sonoff iFan02 (ESP8285) - GPIO_KEY1, // GPIO00 Virtual button 1 + GPIO_KEY1, // GPIO00 Virtual button 1 as feedback from RC GPIO_USER, // GPIO01 Serial RXD and Optional sensor 0, // GPIO02 Optional sensor GPIO_USER, // GPIO03 Serial TXD and Optional sensor - GPIO_REL3, // GPIO04 Relay 3 (0 = Off, 1 = On) - GPIO_REL2, // GPIO05 Relay 2 (0 = Off, 1 = On) + GPIO_REL3, // GPIO04 Relay 3 (0 = Off, 1 = On) controlling the fan + GPIO_REL2, // GPIO05 Relay 2 (0 = Off, 1 = On) controlling the fan 0, 0, 0, // Flash connection - GPIO_KEY2, // GPIO09 Virtual button 2 - GPIO_KEY3, // GPIO10 Virtual button 3 + GPIO_KEY2, // GPIO09 Virtual button 2 as feedback from RC + GPIO_KEY3, // GPIO10 Virtual button 3 as feedback from RC 0, // Flash connection - GPIO_REL1, // GPIO12 Relay 1 (0 = Off, 1 = On) + GPIO_REL1, // GPIO12 Relay 1 (0 = Off, 1 = On) controlling the light GPIO_LED1_INV, // GPIO13 Blue Led on PCA (0 = On, 1 = Off) - GPIO_KEY4, // GPIO14 Virtual button 4 - GPIO_REL4, // GPIO15 Relay 4 (0 = Off, 1 = On) + GPIO_KEY4, // GPIO14 Virtual button 4 as feedback from RC + GPIO_REL4, // GPIO15 Relay 4 (0 = Off, 1 = On) controlling the fan 0, 0 } }; diff --git a/sonoff/xdrv_01_mqtt.ino b/sonoff/xdrv_01_mqtt.ino index 77c1e88f4..aa43dd85d 100644 --- a/sonoff/xdrv_01_mqtt.ino +++ b/sonoff/xdrv_01_mqtt.ino @@ -283,15 +283,24 @@ void MqttPublishPowerState(byte device) char scommand[33]; if ((device < 1) || (device > devices_present)) { device = 1; } - GetPowerDevice(scommand, device, sizeof(scommand), Settings.flag.device_index_enable); - GetTopic_P(stopic, STAT, mqtt_topic, (Settings.flag.mqtt_response) ? scommand : S_RSLT_RESULT); - snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, scommand, GetStateText(bitRead(power, device -1))); - MqttPublish(stopic); + if ((SONOFF_IFAN02 == Settings.module) && (device > 1)) { // Do not report status of fan relays + if (GetFanspeed() < 4) { + snprintf_P(scommand, sizeof(scommand), PSTR(D_CMND_FANSPEED)); + GetTopic_P(stopic, STAT, mqtt_topic, (Settings.flag.mqtt_response) ? scommand : S_RSLT_RESULT); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, scommand, GetFanspeed()); + MqttPublish(stopic); + } + } else { + GetPowerDevice(scommand, device, sizeof(scommand), Settings.flag.device_index_enable); + GetTopic_P(stopic, STAT, mqtt_topic, (Settings.flag.mqtt_response) ? scommand : S_RSLT_RESULT); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, scommand, GetStateText(bitRead(power, device -1))); + MqttPublish(stopic); - GetTopic_P(stopic, STAT, mqtt_topic, scommand); - snprintf_P(mqtt_data, sizeof(mqtt_data), GetStateText(bitRead(power, device -1))); - MqttPublish(stopic, Settings.flag.mqtt_power_retain); + GetTopic_P(stopic, STAT, mqtt_topic, scommand); + snprintf_P(mqtt_data, sizeof(mqtt_data), GetStateText(bitRead(power, device -1))); + MqttPublish(stopic, Settings.flag.mqtt_power_retain); + } } void MqttPublishPowerBlinkState(byte device) diff --git a/sonoff/xdrv_02_webserver.ino b/sonoff/xdrv_02_webserver.ino index c9f3df134..f658a2098 100644 --- a/sonoff/xdrv_02_webserver.ino +++ b/sonoff/xdrv_02_webserver.ino @@ -313,6 +313,9 @@ const char HTTP_END[] PROGMEM = "" ""; +const char HTTP_DEVICE_CONTROL[] PROGMEM = ""; +const char HTTP_DEVICE_STATE[] PROGMEM = "%s%s"; // {c} = %'>
"), - 100 / devices_present, idx, (devices_present < 5) ? D_BUTTON_TOGGLE : "", (devices_present > 1) ? stemp : ""); + if (SONOFF_IFAN02 == Settings.module) { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_DEVICE_CONTROL, 36, 1, D_BUTTON_TOGGLE, ""); page += mqtt_data; + for (byte i = 0; i < 4; i++) { + snprintf_P(stemp, sizeof(stemp), PSTR("%d"), i); + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_DEVICE_CONTROL, 16, i +2, stemp, ""); + page += mqtt_data; + } + } else { + for (byte idx = 1; idx <= devices_present; idx++) { + snprintf_P(stemp, sizeof(stemp), PSTR(" %d"), idx); + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_DEVICE_CONTROL, + 100 / devices_present, idx, (devices_present < 5) ? D_BUTTON_TOGGLE : "", (devices_present > 1) ? stemp : ""); + page += mqtt_data; + } } page += F(""); } @@ -592,10 +605,16 @@ void HandleAjaxStatusRefresh() WebGetArg("o", tmp, sizeof(tmp)); if (strlen(tmp)) { ShowWebSource(SRC_WEBGUI); - if (SONOFF_IFAN02 == Settings.module) { // QandD - ExecuteCommandPower(1, POWER_TOGGLE, SRC_IGNORE); + uint8_t device = atoi(tmp); + if (SONOFF_IFAN02 == Settings.module) { + if (device < 2) { + ExecuteCommandPower(1, POWER_TOGGLE, SRC_IGNORE); + } else { + snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_FANSPEED " %d"), device -2); + ExecuteCommand(svalue, SRC_WEBGUI); + } } else { - ExecuteCommandPower(atoi(tmp), POWER_TOGGLE, SRC_IGNORE); + ExecuteCommandPower(device, POWER_TOGGLE, SRC_IGNORE); } } WebGetArg("d", tmp, sizeof(tmp)); @@ -627,10 +646,19 @@ void HandleAjaxStatusRefresh() if (devices_present) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s{t}"), mqtt_data); uint8_t fsize = (devices_present < 5) ? 70 - (devices_present * 8) : 32; - for (byte idx = 1; idx <= devices_present; idx++) { - snprintf_P(svalue, sizeof(svalue), PSTR("%d"), bitRead(power, idx -1)); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s
"), // {c} = %'>