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 BUTTON_INVERT 0x02 // Invert bitmask
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_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));
}
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; }
@ -251,12 +253,23 @@ void ButtonInit(void) {
else {
XdrvMailbox.index = i;
if (XdrvCall(FUNC_ADD_BUTTON)) {
AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Add button %d"), i);
bitSet(Button.virtual_pin_used, i);
/*
At entry:
XdrvMailbox.index = key index
At exit:
XdrvMailbox.index bit 0 = current state
XdrvMailbox.index bit 1 = invert signal
*/
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;
}
}
@ -267,6 +280,9 @@ void ButtonInit(void) {
}
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) {
Button.first_change = true;
TickerButton.attach_ms((ac_detect) ? BUTTON_FAST_PROBE_INTERVAL : BUTTON_PROBE_INTERVAL, ButtonProbe);
@ -371,6 +387,7 @@ void ButtonHandler(void) {
if (button_present) {
XdrvMailbox.index = button_index;
XdrvMailbox.payload = button;
XdrvMailbox.command_code = Button.last_state[button_index];
if (XdrvCall(FUNC_BUTTON_PRESSED)) {
// Serviced
}

View File

@ -236,12 +236,20 @@ void SwitchInit(void) {
else {
XdrvMailbox.index = i;
if (XdrvCall(FUNC_ADD_SWITCH)) {
AddLog(LOG_LEVEL_DEBUG, PSTR("SWT: Add switch %d"), i);
bitSet(Switch.virtual_pin_used, i);
/*
At entry:
XdrvMailbox.index = switch index
At exit:
XdrvMailbox.index bit 0 = current state
*/
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;
}
}
@ -252,6 +260,9 @@ void SwitchInit(void) {
}
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) {
Switch.first_change = true;
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;
int switch_offset;
int button_offset;
uint8_t last_button[3];
uint8_t pin_register_cs;
uint8_t pin_mcp23s17_int;
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) {
uint8_t iodir = pin < 8 ? SP4_MCP23S17_IODIRA : SP4_MCP23S17_IODIRB;
uint8_t gppu = pin < 8 ? SP4_MCP23S17_GPPUA : SP4_MCP23S17_GPPUB;
@ -216,7 +205,13 @@ void ShellyPro4Init(void) {
bit 14 = output - Relay O3
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++) {
SP4Mcp23S17PinMode(sp4_switch_pin[i], INPUT); // Switch1..4
@ -231,7 +226,6 @@ void ShellyPro4Init(void) {
SP4Mcp23S17PinMode(4, OUTPUT); // Reset display, ADE7943
SP4Mcp23S17DigitalWrite(4, 1);
}
void ShellyPro4Reset(void) {
@ -241,30 +235,30 @@ void ShellyPro4Reset(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; }
uint32_t index = XdrvMailbox.index - SPro.button_offset;
if (index > 2) { return false; }
XdrvMailbox.payload = SP4Mcp23S17DigitalRead(sp4_button_pin[index]);
if (index > 2) { return false; } // Support three buttons
XdrvMailbox.index = SP4Mcp23S17DigitalRead(sp4_button_pin[index]);
return true;
}
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; }
uint32_t index = XdrvMailbox.index - SPro.switch_offset;
if (index > 3) { return false; }
XdrvMailbox.payload = SP4Mcp23S17DigitalRead(sp4_switch_pin[index]);
if (index > 3) { return false; } // Support four switches
XdrvMailbox.index = SP4Mcp23S17DigitalRead(sp4_switch_pin[index]);
return true;
}
void ShellyProUpdateSwitches(void) {
if (SPro.detected != 4) { return; }
if (digitalRead(SPro.pin_mcp23s17_int)) { return; }
if (SPro.detected != 4) { return; } // Only support Shelly Pro 4
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
uint32_t state;
@ -279,14 +273,14 @@ void ShellyProUpdateSwitches(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;
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;
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);
@ -299,10 +293,8 @@ bool ShellyProButton(void) {
case 2: // Ok
break;
}
result = true; // Disable further button processing
}
SPro.last_button[button_index] = button;
return result;
return true; // Disable further button processing
}
/*********************************************************************************************\
@ -323,11 +315,11 @@ void ShellyProUpdate(void) {
*/
uint8_t val = SPro.power | SPro.ledlink;
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
SPI.transfer(val); // Write 74HC595 shift register
SPI.transfer(val); // Write 74HC595 shift register
SPI.endTransaction();
// delayMicroseconds(2); // Wait for SPI clock to stop
digitalWrite(SPro.pin_register_cs, 1); // Latch data
delayMicroseconds(1); // Shelly 10mS
// delayMicroseconds(2); // Wait for SPI clock to stop
digitalWrite(SPro.pin_register_cs, 1); // Latch data
delayMicroseconds(1); // Shelly 10mS
digitalWrite(SPro.pin_register_cs, 0);
}
@ -337,18 +329,18 @@ void ShellyProUpdate(void) {
void ShellyProPreInit(void) {
if ((SPI_MOSI_MISO == TasmotaGlobal.spi_enabled) &&
PinUsed(GPIO_SPI_CS) && // 74HC595 rclk / MCP23S17
TasmotaGlobal.gpio_optiona.shelly_pro) { // Option_A7
PinUsed(GPIO_SPI_CS) && // 74HC595 rclk / MCP23S17
TasmotaGlobal.gpio_optiona.shelly_pro) { // Option_A7
if (PinUsed(GPIO_SWT1) || PinUsed(GPIO_KEY1)) {
SPro.detected = 1; // Shelly Pro 1
SPro.detected = 1; // Shelly Pro 1
if (PinUsed(GPIO_SWT1, 1) || PinUsed(GPIO_KEY1, 1)) {
SPro.detected = 2; // Shelly Pro 2
SPro.detected = 2; // Shelly Pro 2
}
SPro.ledlink = 0x18; // Blue led on - set by first call ShellyProPower() - Shelly 1/2
SPro.ledlink = 0x18; // Blue led on - set by first call ShellyProPower() - Shelly 1/2
}
if (SHELLY_PRO_4_PIN_SPI_CS == Pin(GPIO_SPI_CS)) {
SPro.detected = 4; // Shelly Pro 4PM (No SWT or KEY)
SPro.detected = 4; // Shelly Pro 4PM (No SWT or KEY)
}
if (SPro.detected) {
@ -360,13 +352,12 @@ void ShellyProPreInit(void) {
SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1);
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
pinMode(SPro.pin_mcp23s17_int, INPUT);
// Init MCP23S17
ShellyPro4Init();
ShellyPro4Init(); // Init MCP23S17
} else {
digitalWrite(SPro.pin_register_cs, 0);
digitalWrite(SPro.pin_register_cs, 0); // Prep 74HC595 rclk
}
}
}
@ -374,10 +365,10 @@ void ShellyProPreInit(void) {
void ShellyProInit(void) {
int pin_lan_reset = SHELLY_PRO_PIN_LAN8720_RESET; // GPIO5 = LAN8720 nRST
// delay(30); // (t-purstd) This pin must be brought low for a minimum of 25 mS after power on
// delay(30); // (t-purstd) This pin must be brought low for a minimum of 25 mS after power on
digitalWrite(pin_lan_reset, 0);
pinMode(pin_lan_reset, OUTPUT);
delay(1); // (t-rstia) This pin must be brought low for a minimum of 100 uS
delay(1); // (t-rstia) This pin must be brought low for a minimum of 100 uS
digitalWrite(pin_lan_reset, 1);
AddLog(LOG_LEVEL_INFO, PSTR("HDW: Shelly Pro %d%s initialized"), SPro.detected, (PinUsed(GPIO_ADE7953_CS))?"PM":"");
@ -386,13 +377,13 @@ void ShellyProInit(void) {
void ShellyProPower(void) {
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;
for (uint32_t i = 0; i < 4; i++) {
power_t state = rpower &1;
SP4Mcp23S17DigitalWrite(sp4_relay_pin[i], state);
rpower >>= 1; // Select next power
rpower >>= 1; // Select next power
}
} else {
SPro.power = XdrvMailbox.index &3;
@ -430,12 +421,12 @@ void ShellyProLedLink(void) {
- Green light indicator will be on if in STA mode and connected to a Wi-Fi network.
*/
SPro.last_update = TasmotaGlobal.uptime;
uint32_t ledlink = 0x1C; // All leds off
uint32_t ledlink = 0x1C; // All leds off
if (XdrvMailbox.index) {
ledlink &= 0xFB; // Blue blinks if wifi/mqtt lost
ledlink &= 0xFB; // Blue blinks if wifi/mqtt lost
}
else if (!TasmotaGlobal.global_state.wifi_down) {
ledlink &= 0xF7; // Green On
ledlink &= 0xF7; // Green On
}
ShellyProUpdateLedLink(ledlink);
}
@ -470,9 +461,11 @@ bool Xdrv88(uint32_t function) {
case FUNC_EVERY_50_MSECOND:
ShellyProUpdateSwitches();
break;
/*
case FUNC_BUTTON_PRESSED:
result = ShellyProButton();
break;
*/
case FUNC_EVERY_SECOND:
ShellyProLedLinkWifiOff();
break;

View File

@ -274,19 +274,6 @@ void Ade7953Write(uint16_t reg, uint32_t val) {
#ifdef USE_ESP32_SPI
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();
SPI.transfer16(reg);
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
}
Ade7953SpiDisable();
} else {
#endif // USE_ESP32_SPI
Wire.beginTransmission(ADE7953_ADDR);
@ -318,18 +304,6 @@ int32_t Ade7953Read(uint16_t reg) {
if (size) {
#ifdef USE_ESP32_SPI
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();
SPI.transfer16(reg);
SPI.transfer(0x80); // Read
@ -337,7 +311,6 @@ int32_t Ade7953Read(uint16_t reg) {
response = response << 8 | SPI.transfer(0xFF); // receive DATA (MSB first)
}
Ade7953SpiDisable();
} else {
#endif // USE_ESP32_SPI
Wire.beginTransmission(ADE7953_ADDR);