Fix Shelly Pro 4PM auto reset

This commit is contained in:
Theo Arends 2023-01-22 16:41:25 +01:00
parent 3f73d5a49d
commit 88dd5f7f50
4 changed files with 83 additions and 89 deletions

View File

@ -27,6 +27,8 @@
#define MAX_RELAY_BUTTON1 5 // Max number of relay controlled by BUTTON1 #define MAX_RELAY_BUTTON1 5 // Max number of relay controlled by BUTTON1
#define BUTTON_INVERT 0x02 // Invert bitmask
const uint8_t BUTTON_PROBE_INTERVAL = 10; // Time in milliseconds between button input probe const uint8_t BUTTON_PROBE_INTERVAL = 10; // Time in milliseconds between button input probe
const uint8_t BUTTON_FAST_PROBE_INTERVAL = 2; // Time in milliseconds between button input probe for AC detection const uint8_t BUTTON_FAST_PROBE_INTERVAL = 2; // Time in milliseconds between button input probe for AC detection
const uint8_t BUTTON_AC_PERIOD = (20 + BUTTON_FAST_PROBE_INTERVAL - 1) / BUTTON_FAST_PROBE_INTERVAL; // Duration of an AC wave in probe intervals const uint8_t BUTTON_AC_PERIOD = (20 + BUTTON_FAST_PROBE_INTERVAL - 1) / BUTTON_FAST_PROBE_INTERVAL; // Duration of an AC wave in probe intervals
@ -134,7 +136,7 @@ void ButtonProbe(void) {
not_activated = (digitalRead(Pin(GPIO_KEY1, i)) != bitRead(Button.inverted_mask, i)); not_activated = (digitalRead(Pin(GPIO_KEY1, i)) != bitRead(Button.inverted_mask, i));
} }
else if (bitRead(Button.virtual_pin_used, i)) { else if (bitRead(Button.virtual_pin_used, i)) {
not_activated = bitRead(Button.virtual_pin, i); not_activated = (bitRead(Button.virtual_pin, i) != bitRead(Button.inverted_mask, i));
} }
else { continue; } else { continue; }
@ -251,12 +253,23 @@ void ButtonInit(void) {
else { else {
XdrvMailbox.index = i; XdrvMailbox.index = i;
if (XdrvCall(FUNC_ADD_BUTTON)) { if (XdrvCall(FUNC_ADD_BUTTON)) {
/*
AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Add button %d"), i); At entry:
XdrvMailbox.index = key index
bitSet(Button.virtual_pin_used, i); At exit:
XdrvMailbox.index bit 0 = current state
XdrvMailbox.index bit 1 = invert signal
*/
Button.present++; Button.present++;
Button.last_state[i] = XdrvMailbox.payload; bitSet(Button.virtual_pin_used, i); // This pin is used
bool state = (XdrvMailbox.index &1);
ButtonSetVirtualPinState(i, state); // Virtual hardware pin state
bool invert = (XdrvMailbox.index &BUTTON_INVERT);
if (invert) { ButtonInvertFlag(i); } // Set inverted flag
Button.last_state[i] = (bitRead(Button.virtual_pin, i) != bitRead(Button.inverted_mask, i));
AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Add vButton%d, State %d, Info %02X"), Button.present, Button.last_state[i], XdrvMailbox.index);
used = true; used = true;
} }
} }
@ -267,6 +280,9 @@ void ButtonInit(void) {
} }
Button.debounced_state[i] = Button.last_state[i]; Button.debounced_state[i] = Button.last_state[i];
} }
// AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: vPinUsed %08X, State %08X, Invert %08X"), Button.virtual_pin_used, Button.virtual_pin, Button.inverted_mask);
if (Button.present) { if (Button.present) {
Button.first_change = true; Button.first_change = true;
TickerButton.attach_ms((ac_detect) ? BUTTON_FAST_PROBE_INTERVAL : BUTTON_PROBE_INTERVAL, ButtonProbe); TickerButton.attach_ms((ac_detect) ? BUTTON_FAST_PROBE_INTERVAL : BUTTON_PROBE_INTERVAL, ButtonProbe);
@ -371,6 +387,7 @@ void ButtonHandler(void) {
if (button_present) { if (button_present) {
XdrvMailbox.index = button_index; XdrvMailbox.index = button_index;
XdrvMailbox.payload = button; XdrvMailbox.payload = button;
XdrvMailbox.command_code = Button.last_state[button_index];
if (XdrvCall(FUNC_BUTTON_PRESSED)) { if (XdrvCall(FUNC_BUTTON_PRESSED)) {
// Serviced // Serviced
} }

View File

@ -236,12 +236,20 @@ void SwitchInit(void) {
else { else {
XdrvMailbox.index = i; XdrvMailbox.index = i;
if (XdrvCall(FUNC_ADD_SWITCH)) { if (XdrvCall(FUNC_ADD_SWITCH)) {
/*
AddLog(LOG_LEVEL_DEBUG, PSTR("SWT: Add switch %d"), i); At entry:
XdrvMailbox.index = switch index
bitSet(Switch.virtual_pin_used, i); At exit:
XdrvMailbox.index bit 0 = current state
*/
Switch.present++; Switch.present++;
Switch.last_state[i] = XdrvMailbox.payload; bitSet(Switch.virtual_pin_used, i); // This pin is used
bool state = (XdrvMailbox.index &1);
SwitchSetVirtualPinState(i, state); // Virtual hardware pin state
Switch.last_state[i] = bitRead(Switch.virtual_pin, i);
AddLog(LOG_LEVEL_DEBUG, PSTR("SWT: Add vSwitch%d, State %d, Info %02X"), Switch.present, Switch.last_state[i], XdrvMailbox.index);
used = true; used = true;
} }
} }
@ -252,6 +260,9 @@ void SwitchInit(void) {
} }
Switch.debounced_state[i] = Switch.last_state[i]; Switch.debounced_state[i] = Switch.last_state[i];
} }
// AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: vPinUsed %08X, State %08X"), Switch.virtual_pin_used, Switch.virtual_pin);
if (Switch.present) { if (Switch.present) {
Switch.first_change = true; Switch.first_change = true;
TickerSwitch.attach_ms((ac_detect) ? SWITCH_FAST_PROBE_INTERVAL : SWITCH_PROBE_INTERVAL, SwitchProbe); TickerSwitch.attach_ms((ac_detect) ? SWITCH_FAST_PROBE_INTERVAL : SWITCH_PROBE_INTERVAL, SwitchProbe);

View File

@ -47,7 +47,6 @@ struct SPro {
uint32_t probe_pin; uint32_t probe_pin;
int switch_offset; int switch_offset;
int button_offset; int button_offset;
uint8_t last_button[3];
uint8_t pin_register_cs; uint8_t pin_register_cs;
uint8_t pin_mcp23s17_int; uint8_t pin_mcp23s17_int;
uint8_t ledlink; uint8_t ledlink;
@ -151,16 +150,6 @@ void SP4Mcp23S17Update(uint8_t pin, bool pin_value, uint8_t reg_addr) {
} }
} }
void SP4Mcp23S17Setup(void) {
SP4Mcp23S17Write(SP4_MCP23S17_IOCONA, 0b01011000); // Enable INT mirror, Slew rate disabled, HAEN pins for addressing
SP4Mcp23S17Write(SP4_MCP23S17_GPINTENA, 0x6F); // Enable interrupt on change
SP4Mcp23S17Write(SP4_MCP23S17_GPINTENB, 0x80); // Enable interrupt on change
// Read current output register state
SP4Mcp23S17Read(SP4_MCP23S17_OLATA, &sp4_mcp23s17_olata);
SP4Mcp23S17Read(SP4_MCP23S17_OLATB, &sp4_mcp23s17_olatb);
}
void SP4Mcp23S17PinMode(uint8_t pin, uint8_t flags) { void SP4Mcp23S17PinMode(uint8_t pin, uint8_t flags) {
uint8_t iodir = pin < 8 ? SP4_MCP23S17_IODIRA : SP4_MCP23S17_IODIRB; uint8_t iodir = pin < 8 ? SP4_MCP23S17_IODIRA : SP4_MCP23S17_IODIRB;
uint8_t gppu = pin < 8 ? SP4_MCP23S17_GPPUA : SP4_MCP23S17_GPPUB; uint8_t gppu = pin < 8 ? SP4_MCP23S17_GPPUA : SP4_MCP23S17_GPPUB;
@ -216,7 +205,13 @@ void ShellyPro4Init(void) {
bit 14 = output - Relay O3 bit 14 = output - Relay O3
bit 15 = input - Switch4 bit 15 = input - Switch4
*/ */
SP4Mcp23S17Setup(); SP4Mcp23S17Write(SP4_MCP23S17_IOCONA, 0b01011000); // Enable INT mirror, Slew rate disabled, HAEN pins for addressing
SP4Mcp23S17Write(SP4_MCP23S17_GPINTENA, 0x6F); // Enable interrupt on change
SP4Mcp23S17Write(SP4_MCP23S17_GPINTENB, 0x80); // Enable interrupt on change
// Read current output register state
SP4Mcp23S17Read(SP4_MCP23S17_OLATA, &sp4_mcp23s17_olata);
SP4Mcp23S17Read(SP4_MCP23S17_OLATB, &sp4_mcp23s17_olatb);
for (uint32_t i = 0; i < 4; i++) { for (uint32_t i = 0; i < 4; i++) {
SP4Mcp23S17PinMode(sp4_switch_pin[i], INPUT); // Switch1..4 SP4Mcp23S17PinMode(sp4_switch_pin[i], INPUT); // Switch1..4
@ -231,7 +226,6 @@ void ShellyPro4Init(void) {
SP4Mcp23S17PinMode(4, OUTPUT); // Reset display, ADE7943 SP4Mcp23S17PinMode(4, OUTPUT); // Reset display, ADE7943
SP4Mcp23S17DigitalWrite(4, 1); SP4Mcp23S17DigitalWrite(4, 1);
} }
void ShellyPro4Reset(void) { void ShellyPro4Reset(void) {
@ -241,30 +235,30 @@ void ShellyPro4Reset(void) {
} }
bool ShellyProAddButton(void) { bool ShellyProAddButton(void) {
if (SPro.detected != 4) { return false; } if (SPro.detected != 4) { return false; } // Only support Shelly Pro 4
if (SPro.button_offset < 0) { SPro.button_offset = XdrvMailbox.index; } if (SPro.button_offset < 0) { SPro.button_offset = XdrvMailbox.index; }
uint32_t index = XdrvMailbox.index - SPro.button_offset; uint32_t index = XdrvMailbox.index - SPro.button_offset;
if (index > 2) { return false; } if (index > 2) { return false; } // Support three buttons
XdrvMailbox.payload = SP4Mcp23S17DigitalRead(sp4_button_pin[index]); XdrvMailbox.index = SP4Mcp23S17DigitalRead(sp4_button_pin[index]);
return true; return true;
} }
bool ShellyProAddSwitch(void) { bool ShellyProAddSwitch(void) {
if (SPro.detected != 4) { return false; } if (SPro.detected != 4) { return false; } // Only support Shelly Pro 4
if (SPro.switch_offset < 0) { SPro.switch_offset = XdrvMailbox.index; } if (SPro.switch_offset < 0) { SPro.switch_offset = XdrvMailbox.index; }
uint32_t index = XdrvMailbox.index - SPro.switch_offset; uint32_t index = XdrvMailbox.index - SPro.switch_offset;
if (index > 3) { return false; } if (index > 3) { return false; } // Support four switches
XdrvMailbox.payload = SP4Mcp23S17DigitalRead(sp4_switch_pin[index]); XdrvMailbox.index = SP4Mcp23S17DigitalRead(sp4_switch_pin[index]);
return true; return true;
} }
void ShellyProUpdateSwitches(void) { void ShellyProUpdateSwitches(void) {
if (SPro.detected != 4) { return; } if (SPro.detected != 4) { return; } // Only support Shelly Pro 4
if (digitalRead(SPro.pin_mcp23s17_int)) { return; } if (digitalRead(SPro.pin_mcp23s17_int)) { return; } // Poll interrupt
uint32_t gpio = SP4Mcp23S17ReadGpio(); uint32_t gpio = SP4Mcp23S17ReadGpio(); // Read gpio and clear interrupt
AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Input detected 0x%04X"), gpio); // AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Input detected 0x%04X"), gpio);
// Propagate state // Propagate state
uint32_t state; uint32_t state;
@ -279,14 +273,14 @@ void ShellyProUpdateSwitches(void) {
} }
bool ShellyProButton(void) { bool ShellyProButton(void) {
if (SPro.detected != 4) { return false; } if (SPro.detected != 4) { return false; } // Only support Shelly Pro 4
uint32_t button_index = XdrvMailbox.index - SPro.button_offset; uint32_t button_index = XdrvMailbox.index - SPro.button_offset;
if (button_index > 2) { return false; } // We only support Up, Down, Ok if (button_index > 2) { return false; } // Only support Up, Down, Ok
bool result = false;
uint32_t button = XdrvMailbox.payload; uint32_t button = XdrvMailbox.payload;
if ((PRESSED == button) && (NOT_PRESSED == SPro.last_button[button_index])) { // Button pressed uint32_t last_state = XdrvMailbox.command_code;
if ((PRESSED == button) && (NOT_PRESSED == last_state)) { // Button pressed
AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Button %d pressed"), button_index +1); AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Button %d pressed"), button_index +1);
@ -299,10 +293,8 @@ bool ShellyProButton(void) {
case 2: // Ok case 2: // Ok
break; break;
} }
result = true; // Disable further button processing
} }
SPro.last_button[button_index] = button; return true; // Disable further button processing
return result;
} }
/*********************************************************************************************\ /*********************************************************************************************\
@ -360,13 +352,12 @@ void ShellyProPreInit(void) {
SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1); SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1);
if (4 == SPro.detected) { if (4 == SPro.detected) {
digitalWrite(SPro.pin_register_cs, 1); digitalWrite(SPro.pin_register_cs, 1); // Prep MCP23S17 chip select
SPro.pin_mcp23s17_int = SHELLY_PRO_4_PIN_MCP23S17_INT; // GPIO35 = MCP23S17 common interrupt SPro.pin_mcp23s17_int = SHELLY_PRO_4_PIN_MCP23S17_INT; // GPIO35 = MCP23S17 common interrupt
pinMode(SPro.pin_mcp23s17_int, INPUT); pinMode(SPro.pin_mcp23s17_int, INPUT);
// Init MCP23S17 ShellyPro4Init(); // Init MCP23S17
ShellyPro4Init();
} else { } else {
digitalWrite(SPro.pin_register_cs, 0); digitalWrite(SPro.pin_register_cs, 0); // Prep 74HC595 rclk
} }
} }
} }
@ -386,7 +377,7 @@ void ShellyProInit(void) {
void ShellyProPower(void) { void ShellyProPower(void) {
if (4 == SPro.detected) { if (4 == SPro.detected) {
AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Set Power 0x%08X"), XdrvMailbox.index); // AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Set Power 0x%08X"), XdrvMailbox.index);
power_t rpower = XdrvMailbox.index; power_t rpower = XdrvMailbox.index;
for (uint32_t i = 0; i < 4; i++) { for (uint32_t i = 0; i < 4; i++) {
@ -470,9 +461,11 @@ bool Xdrv88(uint32_t function) {
case FUNC_EVERY_50_MSECOND: case FUNC_EVERY_50_MSECOND:
ShellyProUpdateSwitches(); ShellyProUpdateSwitches();
break; break;
/*
case FUNC_BUTTON_PRESSED: case FUNC_BUTTON_PRESSED:
result = ShellyProButton(); result = ShellyProButton();
break; break;
*/
case FUNC_EVERY_SECOND: case FUNC_EVERY_SECOND:
ShellyProLedLinkWifiOff(); ShellyProLedLinkWifiOff();
break; break;

View File

@ -274,19 +274,6 @@ void Ade7953Write(uint16_t reg, uint32_t val) {
#ifdef USE_ESP32_SPI #ifdef USE_ESP32_SPI
if (Ade7953.pin_cs[0] >= 0) { if (Ade7953.pin_cs[0] >= 0) {
/*
digitalWrite(Ade7953.pin_cs[Ade7953.cs_index], 0);
delayMicroseconds(1); // CS 1uS to SCLK edge
SPI.beginTransaction(Ade7953.spi_settings);
SPI.transfer16(reg);
SPI.transfer(0x00); // Write
while (size--) {
SPI.transfer((val >> (8 * size)) & 0xFF); // Write data, MSB first
}
SPI.endTransaction();
delayMicroseconds(2); // CS high 1.2uS after SCLK edge (when writing to COMM_LOCK bit)
digitalWrite(Ade7953.pin_cs[Ade7953.cs_index], 1);
*/
Ade7953SpiEnable(); Ade7953SpiEnable();
SPI.transfer16(reg); SPI.transfer16(reg);
SPI.transfer(0x00); // Write SPI.transfer(0x00); // Write
@ -294,7 +281,6 @@ void Ade7953Write(uint16_t reg, uint32_t val) {
SPI.transfer((val >> (8 * size)) & 0xFF); // Write data, MSB first SPI.transfer((val >> (8 * size)) & 0xFF); // Write data, MSB first
} }
Ade7953SpiDisable(); Ade7953SpiDisable();
} else { } else {
#endif // USE_ESP32_SPI #endif // USE_ESP32_SPI
Wire.beginTransmission(ADE7953_ADDR); Wire.beginTransmission(ADE7953_ADDR);
@ -318,18 +304,6 @@ int32_t Ade7953Read(uint16_t reg) {
if (size) { if (size) {
#ifdef USE_ESP32_SPI #ifdef USE_ESP32_SPI
if (Ade7953.pin_cs[0] >= 0) { if (Ade7953.pin_cs[0] >= 0) {
/*
digitalWrite(Ade7953.pin_cs[Ade7953.cs_index], 0);
delayMicroseconds(1); // CS 1uS to SCLK edge
SPI.beginTransaction(Ade7953.spi_settings);
SPI.transfer16(reg);
SPI.transfer(0x80); // Read
while (size--) {
response = response << 8 | SPI.transfer(0); // receive DATA (MSB first)
}
SPI.endTransaction();
digitalWrite(Ade7953.pin_cs[Ade7953.cs_index], 1);
*/
Ade7953SpiEnable(); Ade7953SpiEnable();
SPI.transfer16(reg); SPI.transfer16(reg);
SPI.transfer(0x80); // Read SPI.transfer(0x80); // Read
@ -337,7 +311,6 @@ int32_t Ade7953Read(uint16_t reg) {
response = response << 8 | SPI.transfer(0xFF); // receive DATA (MSB first) response = response << 8 | SPI.transfer(0xFF); // receive DATA (MSB first)
} }
Ade7953SpiDisable(); Ade7953SpiDisable();
} else { } else {
#endif // USE_ESP32_SPI #endif // USE_ESP32_SPI
Wire.beginTransmission(ADE7953_ADDR); Wire.beginTransmission(ADE7953_ADDR);