mirror of https://github.com/arendst/Tasmota.git
Add optional USE_SONOFF_IFAN_CONFIG
This commit is contained in:
parent
401d7b9b41
commit
895fbb2e8a
|
@ -21,18 +21,27 @@
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
* Sonoff iFan02, iFan03 and iFan04
|
* Sonoff iFan02, iFan03 and iFan04
|
||||||
*
|
*
|
||||||
* For iFan04 activate below template
|
* For iFan04-H activate below template:
|
||||||
* {"NAME":"Sonoff iFan04-H","GPIO":[32,3200,5735,3232,0,0,256,512,226,320,225,227,0,0],"FLAG":0,"BASE":71}
|
* {"NAME":"Sonoff iFan04-H","GPIO":[32,3200,5735,3232,0,0,256,512,226,320,225,227,0,0],"FLAG":0,"BASE":71}
|
||||||
|
*
|
||||||
|
* #ifdef USE_SONOFF_IFAN_CONFIG
|
||||||
|
* No template change needed. For iFan04-H select
|
||||||
|
* - a rule like: rule3 on file#ifan.dat do {"Name":"iFan04-H","Speed":[0,1,2,4,5,6],"Sequence":[[0,4,5,3],[0,1,2,3],[0,1,2,3],[0,4,5,3]]} endon
|
||||||
|
* - a script like: -y{"Name":"iFan04-H","Speed":[0,1,2,4,5,6],"Sequence":[[0,4,5,3],[0,1,2,3],[0,1,2,3],[0,4,5,3]]}#
|
||||||
|
* - a file called ifan.dat with contents: {"Name":"iFan04-H","Speed":[0,1,2,4,5,6],"Sequence":[[0,4,5,3],[0,1,2,3],[0,1,2,3],[0,4,5,3]]}
|
||||||
|
*
|
||||||
|
* For reference only:
|
||||||
|
* rule3 on file#ifan.dat do {"Name":"iFan03","Speed":[0,1,3,4,5,6],"Sequence":[[0,2,2,2],[0,1,2,4],[1,1,2,5],[4,4,5,3]]} endon
|
||||||
\*********************************************************************************************/
|
\*********************************************************************************************/
|
||||||
|
|
||||||
#define XDRV_22 22
|
#define XDRV_22 22
|
||||||
|
|
||||||
|
//#define USE_SONOFF_IFAN_CONFIG // Enable ifan user config
|
||||||
|
|
||||||
const uint8_t MAX_FAN_SPEED = 4; // Max number of iFan02 fan speeds (0 .. 3)
|
const uint8_t MAX_FAN_SPEED = 4; // Max number of iFan02 fan speeds (0 .. 3)
|
||||||
|
|
||||||
const uint8_t kIFan02Speed[MAX_FAN_SPEED] = { 0x00, 0x01, 0x03, 0x05 };
|
const uint8_t kIFan02Speed[MAX_FAN_SPEED] = { 0x00, 0x01, 0x03, 0x05 };
|
||||||
const uint8_t kIFan03Speed[MAX_FAN_SPEED +2] = { 0x00, 0x01, 0x03, 0x04, 0x05, 0x06 };
|
|
||||||
const uint8_t kIFan04Speed[MAX_FAN_SPEED +2] = { 0x00, 0x01, 0x02, 0x04, 0x05, 0x06 };
|
const uint8_t kIFan04Speed[MAX_FAN_SPEED +2] = { 0x00, 0x01, 0x02, 0x04, 0x05, 0x06 };
|
||||||
const uint8_t kIFan03Sequence[MAX_FAN_SPEED][MAX_FAN_SPEED] = {{0, 2, 2, 2}, {0, 1, 2, 4}, {1, 1, 2, 5}, {4, 4, 5, 3}};
|
|
||||||
const uint8_t kIFan04Sequence[MAX_FAN_SPEED][MAX_FAN_SPEED] = {{0, 4, 5, 3}, {0, 1, 2, 3}, {0, 1, 2, 3}, {0, 4, 5, 3}};
|
const uint8_t kIFan04Sequence[MAX_FAN_SPEED][MAX_FAN_SPEED] = {{0, 4, 5, 3}, {0, 1, 2, 3}, {0, 1, 2, 3}, {0, 4, 5, 3}};
|
||||||
|
|
||||||
const char kSonoffIfanCommands[] PROGMEM = "|" // No prefix
|
const char kSonoffIfanCommands[] PROGMEM = "|" // No prefix
|
||||||
|
@ -41,27 +50,28 @@ const char kSonoffIfanCommands[] PROGMEM = "|" // No prefix
|
||||||
void (* const SonoffIfanCommand[])(void) PROGMEM = {
|
void (* const SonoffIfanCommand[])(void) PROGMEM = {
|
||||||
&CmndFanspeed };
|
&CmndFanspeed };
|
||||||
|
|
||||||
uint8_t ifan_fanspeed_timer = 0;
|
struct IFAN {
|
||||||
uint8_t ifan_fanspeed_goal = 0;
|
uint8_t speed[MAX_FAN_SPEED +2] = { 0x00, 0x01, 0x03, 0x04, 0x05, 0x06 };
|
||||||
bool ifan_receive_flag = false;
|
uint8_t sequence[MAX_FAN_SPEED][MAX_FAN_SPEED] = {{0, 2, 2, 2}, {0, 1, 2, 4}, {1, 1, 2, 5}, {4, 4, 5, 3}};
|
||||||
bool ifan_restart_flag = true;
|
uint8_t fanspeed_timer = 0;
|
||||||
|
uint8_t fanspeed_goal = 0;
|
||||||
|
bool receive_flag = false;
|
||||||
|
bool restart_flag = true;
|
||||||
|
} Ifan;
|
||||||
|
|
||||||
/*********************************************************************************************/
|
/*********************************************************************************************/
|
||||||
|
|
||||||
bool IsModuleIfan(void)
|
bool IsModuleIfan(void) {
|
||||||
{
|
|
||||||
return ((SONOFF_IFAN02 == TasmotaGlobal.module_type) || (SONOFF_IFAN03 == TasmotaGlobal.module_type));
|
return ((SONOFF_IFAN02 == TasmotaGlobal.module_type) || (SONOFF_IFAN03 == TasmotaGlobal.module_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t MaxFanspeed(void)
|
uint8_t MaxFanspeed(void) {
|
||||||
{
|
|
||||||
return MAX_FAN_SPEED;
|
return MAX_FAN_SPEED;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t GetFanspeed(void)
|
uint8_t GetFanspeed(void) {
|
||||||
{
|
if (Ifan.fanspeed_timer) {
|
||||||
if (ifan_fanspeed_timer) {
|
return Ifan.fanspeed_goal; // Do not show sequence fanspeed
|
||||||
return ifan_fanspeed_goal; // Do not show sequence fanspeed
|
|
||||||
} else {
|
} else {
|
||||||
/* Fanspeed is controlled by relay 2, 3 and 4 as in Sonoff 4CH.
|
/* Fanspeed is controlled by relay 2, 3 and 4 as in Sonoff 4CH.
|
||||||
000x = 0
|
000x = 0
|
||||||
|
@ -77,28 +87,26 @@ uint8_t GetFanspeed(void)
|
||||||
|
|
||||||
/*********************************************************************************************/
|
/*********************************************************************************************/
|
||||||
|
|
||||||
void SonoffIFanSetFanspeed(uint8_t fanspeed, bool sequence)
|
void SonoffIFanSetFanspeed(uint8_t fanspeed, bool sequence) {
|
||||||
{
|
Ifan.fanspeed_timer = 0; // Stop any sequence
|
||||||
ifan_fanspeed_timer = 0; // Stop any sequence
|
Ifan.fanspeed_goal = fanspeed;
|
||||||
ifan_fanspeed_goal = fanspeed;
|
|
||||||
|
|
||||||
uint8_t fanspeed_now = GetFanspeed();
|
uint8_t fanspeed_now = GetFanspeed();
|
||||||
|
|
||||||
if (fanspeed == fanspeed_now) { return; }
|
if (fanspeed == fanspeed_now) { return; }
|
||||||
|
|
||||||
uint8_t fans = kIFan02Speed[fanspeed];
|
uint8_t fans = kIFan02Speed[fanspeed];
|
||||||
if (SONOFF_IFAN03 == TasmotaGlobal.module_type) {
|
if (SONOFF_IFAN03 == TasmotaGlobal.module_type) {
|
||||||
if (sequence) {
|
if (sequence) {
|
||||||
fanspeed = (TasmotaGlobal.gpio_optiona.ifan04_h) ? kIFan04Sequence[fanspeed_now][ifan_fanspeed_goal] : kIFan03Sequence[fanspeed_now][ifan_fanspeed_goal];
|
fanspeed = Ifan.sequence[fanspeed_now][Ifan.fanspeed_goal];
|
||||||
if (fanspeed != ifan_fanspeed_goal) {
|
if (fanspeed != Ifan.fanspeed_goal) {
|
||||||
if (0 == fanspeed_now) {
|
if (0 == fanspeed_now) {
|
||||||
ifan_fanspeed_timer = 20; // Need extra time to power up fan
|
Ifan.fanspeed_timer = 20; // Need extra time to power up fan
|
||||||
} else {
|
} else {
|
||||||
ifan_fanspeed_timer = 2;
|
Ifan.fanspeed_timer = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fans = (TasmotaGlobal.gpio_optiona.ifan04_h) ? kIFan04Speed[fanspeed] : kIFan03Speed[fanspeed];
|
fans = Ifan.speed[fanspeed];
|
||||||
}
|
}
|
||||||
for (uint32_t i = 2; i < 5; i++) {
|
for (uint32_t i = 2; i < 5; i++) {
|
||||||
uint8_t state = (fans &1) + POWER_OFF_NO_STATE; // Add no publishPowerState
|
uint8_t state = (fans &1) + POWER_OFF_NO_STATE; // Add no publishPowerState
|
||||||
|
@ -113,8 +121,7 @@ void SonoffIFanSetFanspeed(uint8_t fanspeed, bool sequence)
|
||||||
|
|
||||||
/*********************************************************************************************/
|
/*********************************************************************************************/
|
||||||
|
|
||||||
void SonoffIfanReceived(void)
|
void SonoffIfanReceived(void) {
|
||||||
{
|
|
||||||
char svalue[32];
|
char svalue[32];
|
||||||
|
|
||||||
uint8_t mode = TasmotaGlobal.serial_in_buffer[3];
|
uint8_t mode = TasmotaGlobal.serial_in_buffer[3];
|
||||||
|
@ -159,15 +166,14 @@ void SonoffIfanReceived(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SonoffIfanSerialInput(void)
|
bool SonoffIfanSerialInput(void) {
|
||||||
{
|
|
||||||
if (SONOFF_IFAN03 != TasmotaGlobal.module_type) { return false; }
|
if (SONOFF_IFAN03 != TasmotaGlobal.module_type) { return false; }
|
||||||
|
|
||||||
if (0xAA == TasmotaGlobal.serial_in_byte) { // 0xAA - Start of text
|
if (0xAA == TasmotaGlobal.serial_in_byte) { // 0xAA - Start of text
|
||||||
TasmotaGlobal.serial_in_byte_counter = 0;
|
TasmotaGlobal.serial_in_byte_counter = 0;
|
||||||
ifan_receive_flag = true;
|
Ifan.receive_flag = true;
|
||||||
}
|
}
|
||||||
if (ifan_receive_flag) {
|
if (Ifan.receive_flag) {
|
||||||
TasmotaGlobal.serial_in_buffer[TasmotaGlobal.serial_in_byte_counter++] = TasmotaGlobal.serial_in_byte;
|
TasmotaGlobal.serial_in_buffer[TasmotaGlobal.serial_in_byte_counter++] = TasmotaGlobal.serial_in_byte;
|
||||||
if (TasmotaGlobal.serial_in_byte_counter == 8) {
|
if (TasmotaGlobal.serial_in_byte_counter == 8) {
|
||||||
// AA 55 01 01 00 01 01 04 - Wifi long press - start wifi setup
|
// AA 55 01 01 00 01 01 04 - Wifi long press - start wifi setup
|
||||||
|
@ -186,7 +192,7 @@ bool SonoffIfanSerialInput(void)
|
||||||
}
|
}
|
||||||
if (crc == TasmotaGlobal.serial_in_buffer[7]) {
|
if (crc == TasmotaGlobal.serial_in_buffer[7]) {
|
||||||
SonoffIfanReceived();
|
SonoffIfanReceived();
|
||||||
ifan_receive_flag = false;
|
Ifan.receive_flag = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -199,8 +205,7 @@ bool SonoffIfanSerialInput(void)
|
||||||
* Commands
|
* Commands
|
||||||
\*********************************************************************************************/
|
\*********************************************************************************************/
|
||||||
|
|
||||||
void CmndFanspeed(void)
|
void CmndFanspeed(void) {
|
||||||
{
|
|
||||||
if (XdrvMailbox.data_len > 0) {
|
if (XdrvMailbox.data_len > 0) {
|
||||||
if ('-' == XdrvMailbox.data[0]) {
|
if ('-' == XdrvMailbox.data[0]) {
|
||||||
XdrvMailbox.payload = (int16_t)GetFanspeed() -1;
|
XdrvMailbox.payload = (int16_t)GetFanspeed() -1;
|
||||||
|
@ -219,27 +224,84 @@ void CmndFanspeed(void)
|
||||||
|
|
||||||
/*********************************************************************************************/
|
/*********************************************************************************************/
|
||||||
|
|
||||||
bool SonoffIfanInit(void)
|
void SonoffIFanParameters(void) {
|
||||||
{
|
if (TasmotaGlobal.gpio_optiona.ifan04_h) { // GPIO Option_A8
|
||||||
|
memcpy(Ifan.speed, kIFan04Speed, sizeof(Ifan.speed));
|
||||||
|
memcpy(Ifan.sequence, kIFan04Sequence, sizeof(Ifan.sequence));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_SONOFF_IFAN_CONFIG
|
||||||
|
|
||||||
|
String ifantmplt = "";
|
||||||
|
#ifdef USE_UFILESYS
|
||||||
|
ifantmplt = TfsLoadString("/ifan.dat");
|
||||||
|
#endif // USE_UFILESYS
|
||||||
|
#ifdef USE_RULES
|
||||||
|
if (!ifantmplt.length()) {
|
||||||
|
ifantmplt = RuleLoadFile("IFAN.DAT");
|
||||||
|
}
|
||||||
|
#endif // USE_RULES
|
||||||
|
#ifdef USE_SCRIPT
|
||||||
|
if (!ifantmplt.length()) {
|
||||||
|
ifantmplt = ScriptLoadSection(">y");
|
||||||
|
}
|
||||||
|
#endif // USE_SCRIPT
|
||||||
|
if (ifantmplt.length() > 75) {
|
||||||
|
JsonParser parser((char*)ifantmplt.c_str());
|
||||||
|
JsonParserObject root = parser.getRootObject();
|
||||||
|
if (root) {
|
||||||
|
// rule3 on file#ifan.dat do {"Name":"iFan03","Speed":[0,1,3,4,5,6],"Sequence":[[0,2,2,2],[0,1,2,4],[1,1,2,5],[4,4,5,3]]} endon
|
||||||
|
// rule3 on file#ifan.dat do {"Name":"iFan04-H","Speed":[0,1,2,4,5,6],"Sequence":[[0,4,5,3],[0,1,2,3],[0,1,2,3],[0,4,5,3]]} endon
|
||||||
|
JsonParserArray arr_speed = root[PSTR("SPEED")];
|
||||||
|
if (arr_speed) {
|
||||||
|
for (uint32_t i = 0; i < sizeof(Ifan.speed); i++) {
|
||||||
|
JsonParserToken val = arr_speed[i];
|
||||||
|
if (!val) { break; }
|
||||||
|
Ifan.speed[i] = val.getUInt() & 0x07;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
JsonParserArray arr_sequence = root[PSTR("SEQUENCE")];
|
||||||
|
if (arr_sequence) {
|
||||||
|
for (uint32_t j = 0; j < MAX_FAN_SPEED; j++) {
|
||||||
|
JsonParserArray arr_sequence2 = arr_sequence[j];
|
||||||
|
if (!arr_sequence2) { break; }
|
||||||
|
for (uint32_t i = 0; i < MAX_FAN_SPEED; i++) {
|
||||||
|
JsonParserToken val = arr_sequence2[i];
|
||||||
|
if (!val) { break; }
|
||||||
|
Ifan.sequence[j][i] = val.getUInt() & 0x07;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
JsonParserToken val = root[PSTR(D_JSON_NAME)];
|
||||||
|
AddLog(LOG_LEVEL_DEBUG, PSTR("IFN: Loaded%s%s"), (val)?" ":"", (val)?val.getStr():"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // USE_SONOFF_IFAN_CONFIG
|
||||||
|
|
||||||
|
// AddLog(LOG_LEVEL_DEBUG, PSTR("IFN: Speed %6_H, Sequence %16_H"), Ifan.speed, Ifan.sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SonoffIfanInit(void) {
|
||||||
if (SONOFF_IFAN03 == TasmotaGlobal.module_type) {
|
if (SONOFF_IFAN03 == TasmotaGlobal.module_type) {
|
||||||
SetSerial(9600, TS_SERIAL_8N1);
|
SetSerial(9600, TS_SERIAL_8N1);
|
||||||
|
SonoffIFanParameters();
|
||||||
}
|
}
|
||||||
return false; // Continue init chain
|
return false; // Continue init chain
|
||||||
}
|
}
|
||||||
|
|
||||||
void SonoffIfanUpdate(void)
|
void SonoffIfanUpdate(void) {
|
||||||
{
|
|
||||||
if (SONOFF_IFAN03 == TasmotaGlobal.module_type) {
|
if (SONOFF_IFAN03 == TasmotaGlobal.module_type) {
|
||||||
if (ifan_fanspeed_timer) {
|
if (Ifan.fanspeed_timer) {
|
||||||
ifan_fanspeed_timer--;
|
Ifan.fanspeed_timer--;
|
||||||
if (!ifan_fanspeed_timer) {
|
if (!Ifan.fanspeed_timer) {
|
||||||
SonoffIFanSetFanspeed(ifan_fanspeed_goal, false);
|
SonoffIFanSetFanspeed(Ifan.fanspeed_goal, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ifan_restart_flag && (4 == TasmotaGlobal.uptime) && (SONOFF_IFAN02 == TasmotaGlobal.module_type)) { // Microcontroller needs 3 seconds before accepting commands
|
if (Ifan.restart_flag && (4 == TasmotaGlobal.uptime) && (SONOFF_IFAN02 == TasmotaGlobal.module_type)) { // Microcontroller needs 3 seconds before accepting commands
|
||||||
ifan_restart_flag = false;
|
Ifan.restart_flag = false;
|
||||||
SetDevicePower(1, SRC_RETRY); // Sync with default power on state microcontroller being Light ON and Fan OFF
|
SetDevicePower(1, SRC_RETRY); // Sync with default power on state microcontroller being Light ON and Fan OFF
|
||||||
SetDevicePower(TasmotaGlobal.power, SRC_RETRY); // Set required power on state
|
SetDevicePower(TasmotaGlobal.power, SRC_RETRY); // Set required power on state
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue