Bump version v12.3.1.6

- Add ESP32 preliminary support for Matter protocol, milestone 1 (commissioning) by Stephan Hadinger
- Add basic support for Shelly Pro 4PM
This commit is contained in:
Theo Arends 2023-02-05 14:29:42 +01:00
parent 5025e86d75
commit 8bc03bbc06
9 changed files with 432 additions and 592 deletions

View File

@ -3,15 +3,27 @@ All notable changes to this project will be documented in this file.
## [Unreleased] - Development ## [Unreleased] - Development
## [12.3.1.6]
### Added
- ESP32 preliminary support for Matter protocol, milestone 1 (commissioning) by Stephan Hadinger
- Basic support for Shelly Pro 4PM
### Breaking Changed
### Changed
### Fixed
### Removed
## [12.3.1.5] ## [12.3.1.5]
### Added ### Added
- ESP32 support for eigth energy phases/channels - ESP32 support for eigth energy phases/channels
- ESP32 command ``EnergyCols 1..8`` to change number of GUI columns - ESP32 command ``EnergyCols 1..8`` to change number of GUI columns
- ESP32 command ``EnergyDisplay 1..3`` to change GUI column presentation - ESP32 command ``EnergyDisplay 1..3`` to change GUI column presentation
- support for SEN5X gas and air quality sensor by Tyeth Gundry (#17736) - Support for SEN5X gas and air quality sensor by Tyeth Gundry (#17736)
- Berry add ``mdns`` advanced features and query - Berry add ``mdns`` advanced features and query
- ESP32 support for Biomine BioPDU 625x12 (#17857) - ESP32 support for Biomine BioPDU 625x12 (#17857)
- ESP32 preliminary support for Matter protocol, milestone 1 (commissioning)
### Breaking Changed ### Breaking Changed
- Berry energy_ctypes changed with new energy driver - Berry energy_ctypes changed with new energy driver
@ -27,8 +39,6 @@ All notable changes to this project will be documented in this file.
- Broken I2C priority regression from v12.3.1.3 (#17810) - Broken I2C priority regression from v12.3.1.3 (#17810)
- Energy usage and return migrated too small (/10000) regression from v12.3.1.3 - Energy usage and return migrated too small (/10000) regression from v12.3.1.3
### Removed
## [12.3.1.4] 20230127 ## [12.3.1.4] 20230127
### Added ### Added
- Berry ``crypto.EC_P256`` ECDSA signature (required by Matter protocol) - Berry ``crypto.EC_P256`` ECDSA signature (required by Matter protocol)

View File

@ -110,24 +110,28 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
[Complete list](BUILDS.md) of available feature and sensors. [Complete list](BUILDS.md) of available feature and sensors.
## Changelog v12.3.1.5 ## Changelog v12.3.1.6
### Added ### Added
- Support for up to 3 single phase modbus energy monitoring device using generic Energy Modbus driver- Support for RGB displays [#17414](https://github.com/arendst/Tasmota/issues/17414) - Support for up to 3 (ESP8266) or 8 (ESP32) phase modbus energy monitoring device using generic Energy Modbus driver
- Support for RGB displays [#17414](https://github.com/arendst/Tasmota/issues/17414)
- Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 [#17417](https://github.com/arendst/Tasmota/issues/17417) - Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 [#17417](https://github.com/arendst/Tasmota/issues/17417)
- Support for IPv6 only networks on Ethernet (not yet Wifi) - Support for IPv6 only networks on Ethernet (not yet Wifi)
- Support for TM1650 display as used in some clocks by Stefan Oskamp [#17594](https://github.com/arendst/Tasmota/issues/17594) - Support for TM1650 display as used in some clocks by Stefan Oskamp [#17594](https://github.com/arendst/Tasmota/issues/17594)
- Support for PCA9632 4-channel 8-bit PWM driver as light driver by Pascal Heinrich [#17557](https://github.com/arendst/Tasmota/issues/17557) - Support for PCA9632 4-channel 8-bit PWM driver as light driver by Pascal Heinrich [#17557](https://github.com/arendst/Tasmota/issues/17557)
- support for SEN5X gas and air quality sensor by Tyeth Gundry [#17736](https://github.com/arendst/Tasmota/issues/17736) - support for SEN5X gas and air quality sensor by Tyeth Gundry [#17736](https://github.com/arendst/Tasmota/issues/17736)
- Basic support for Shelly Pro 4PM
- Berry support for ``crypto.SHA256`` [#17430](https://github.com/arendst/Tasmota/issues/17430) - Berry support for ``crypto.SHA256`` [#17430](https://github.com/arendst/Tasmota/issues/17430)
- Berry crypto add ``EC_P256`` and ``PBKDF2_HMAC_SHA256`` algorithms required by Matter protocol [#17473](https://github.com/arendst/Tasmota/issues/17473) - Berry crypto add ``EC_P256`` and ``PBKDF2_HMAC_SHA256`` algorithms required by Matter protocol [#17473](https://github.com/arendst/Tasmota/issues/17473)
- Berry crypto add ``random`` to generate series of random bytes - Berry crypto add ``random`` to generate series of random bytes
- Berry crypto add ``HKDF_HMAC_SHA256`` - Berry crypto add ``HKDF_HMAC_SHA256``
- Berry crypto add ``SPAKE2P_Matter`` for Matter support - Berry crypto add ``SPAKE2P_Matter`` for Matter support
- Berry add ``mdns`` advanced features and query
- ESP32 command ``EnergyCols 1..8`` to change number of GUI columns - ESP32 command ``EnergyCols 1..8`` to change number of GUI columns
- ESP32 command ``EnergyDisplay 1..3`` to change GUI column presentation - ESP32 command ``EnergyDisplay 1..3`` to change GUI column presentation
- ESP32 support for eigth energy phases/channels - ESP32 support for eigth energy phases/channels
- ESP32 support for BMPxxx sensors on two I2C busses [#17643](https://github.com/arendst/Tasmota/issues/17643) - ESP32 support for BMPxxx sensors on two I2C busses [#17643](https://github.com/arendst/Tasmota/issues/17643)
- ESP32 support for Biomine BioPDU 625x12 [#17857](https://github.com/arendst/Tasmota/issues/17857) - ESP32 support for Biomine BioPDU 625x12 [#17857](https://github.com/arendst/Tasmota/issues/17857)
- ESP32 preliminary support for Matter protocol, milestone 1 (commissioning) by Stephan Hadinger
### Breaking Changed ### Breaking Changed

View File

@ -39,7 +39,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
uint32_t stop_flash_rotate : 1; // bit 12 (v5.2.0) - SetOption12 - (Settings) Switch between dynamic (0) or fixed (1) slot flash save location uint32_t stop_flash_rotate : 1; // bit 12 (v5.2.0) - SetOption12 - (Settings) Switch between dynamic (0) or fixed (1) slot flash save location
uint32_t button_single : 1; // bit 13 (v5.4.0) - SetOption13 - (Button) Support only single press (1) to speed up button press recognition uint32_t button_single : 1; // bit 13 (v5.4.0) - SetOption13 - (Button) Support only single press (1) to speed up button press recognition
uint32_t interlock : 1; // bit 14 (v5.6.0) - CMND_INTERLOCK - Enable (1) /disable (0) interlock uint32_t interlock : 1; // bit 14 (v5.6.0) - CMND_INTERLOCK - Enable (1) /disable (0) interlock
uint32_t pwm_control : 1; // bit 15 (v5.8.1) - SetOption15 - (Light) Switch between commands PWM (1) or COLOR/DIMMER/CT/CHANNEL (0) uint32_t pwm_control : 1; // bit 15 (v5.8.1) - SetOption15 - (Light) Switch between commands PWM (0) or COLOR/DIMMER/CT/CHANNEL (1)
uint32_t ws_clock_reverse : 1; // bit 16 (v5.8.1) - SetOption16 - (WS2812) Switch between clockwise (0) or counter-clockwise (1) uint32_t ws_clock_reverse : 1; // bit 16 (v5.8.1) - SetOption16 - (WS2812) Switch between clockwise (0) or counter-clockwise (1)
uint32_t decimal_text : 1; // bit 17 (v5.8.1) - SetOption17 - (Light) Switch between decimal (1) or hexadecimal (0) output uint32_t decimal_text : 1; // bit 17 (v5.8.1) - SetOption17 - (Light) Switch between decimal (1) or hexadecimal (0) output
uint32_t light_signal : 1; // bit 18 (v5.10.0c) - SetOption18 - (Light) Pair light signal (1) with CO2 sensor uint32_t light_signal : 1; // bit 18 (v5.10.0c) - SetOption18 - (Light) Pair light signal (1) with CO2 sensor

View File

@ -20,6 +20,6 @@
#ifndef _TASMOTA_VERSION_H_ #ifndef _TASMOTA_VERSION_H_
#define _TASMOTA_VERSION_H_ #define _TASMOTA_VERSION_H_
const uint32_t VERSION = 0x0C030105; // 12.3.1.5 const uint32_t VERSION = 0x0C030106; // 12.3.1.6
#endif // _TASMOTA_VERSION_H_ #endif // _TASMOTA_VERSION_H_

View File

@ -873,8 +873,9 @@ void ResponseAppendFeatures(void)
#if defined(USE_I2C) && defined(USE_SEN5X) #if defined(USE_I2C) && defined(USE_SEN5X)
feature9 |= 0x00008000; // xsns_103_sen5x.ino feature9 |= 0x00008000; // xsns_103_sen5x.ino
#endif #endif
#if defined(USE_ENERGY_SENSOR) && defined(USE_BIOPDU)
// feature9 |= 0x00010000; feature9 |= 0x00010000; // xnrg_24_biopdu.ino
#endif
// feature9 |= 0x00020000; // feature9 |= 0x00020000;
// feature9 |= 0x00040000; // feature9 |= 0x00040000;
// feature9 |= 0x00080000; // feature9 |= 0x00080000;

View File

@ -1,5 +1,5 @@
/* /*
xdrv_88_shelly_pro.ino - Shelly pro family support for Tasmota xdrv_88_esp32_shelly_pro.ino - Shelly pro family support for Tasmota
Copyright (C) 2022 Theo Arends Copyright (C) 2022 Theo Arends
@ -19,86 +19,393 @@
#ifdef ESP32 #ifdef ESP32
#ifdef USE_SPI #ifdef USE_SPI
#ifdef USE_SHELLY_PRO_V1 #ifdef USE_SHELLY_PRO
/*********************************************************************************************\ /*********************************************************************************************\
* Shelly Pro support * Shelly Pro support
* *
* {"NAME":"Shelly Pro 1","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"} * {"NAME":"Shelly Pro 1","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"}
* {"NAME":"Shelly Pro 1PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3459,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"} * {"NAME":"Shelly Pro 1PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3459,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"}
* {"NAME":"Shelly Pro 2","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350;AdcParam2 2,10000,10000,3350"} * {"NAME":"Shelly Pro 2","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350;AdcParam2 2,5600,4700,3350"}
* {"NAME":"Shelly Pro 2PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,9569,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3460,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350;AdcParam2 2,10000,10000,3350"} * {"NAME":"Shelly Pro 2PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,9569,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3460,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350;AdcParam2 2,5600,4700,3350"}
* {"NAME":"Shelly Pro 4PM","GPIO":[0,6210,0,6214,9568,0,0,0,0,0,9569,0,768,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,736,704,3461,0,4736,0,0,672],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"}
* *
* Shelly Pro uses SPI to control one 74HC595 for relays/leds and one ADE7953 (1PM) or two ADE7953 (2PM) for energy monitoring * Shelly Pro 1/2 uses SPI to control one 74HC595 for relays/leds and one ADE7953 (1PM) or two ADE7953 (2PM) for energy monitoring
* Shelly Pro 4 uses an SPI to control one MCP23S17 for buttons/switches/relays/leds and two ADE7953 for energy monitoring and a second SPI for the display
* To use display enable defines USE_DISPLAY, USE_UNIVERSAL_DISPLAY and SHOW_SPLASH. Load file ST7735S_Pro4PM_display.ini as display.ini
\*********************************************************************************************/ \*********************************************************************************************/
#define XDRV_88 88 #define XDRV_88 88
#define SHELLY_PRO_PIN_LAN8720_RESET 5
#define SHELLY_PRO_4_PIN_SPI_CS 16
#define SHELLY_PRO_4_PIN_MCP23S17_INT 35
#define SHELLY_PRO_4_MCP23S17_ADDRESS 0x40
struct SPro { struct SPro {
uint32_t last_update; uint32_t last_update;
uint8_t pin_shift595_rclk; uint16_t input_state;
int8_t switch_offset;
int8_t button_offset;
uint8_t pin_register_cs;
uint8_t pin_mcp23s17_int;
uint8_t ledlink; uint8_t ledlink;
uint8_t power; uint8_t power;
bool detected; bool init_done;
uint8_t detected;
} SPro; } SPro;
/*********************************************************************************************\
* Shelly Pro MCP23S17 support
\*********************************************************************************************/
enum SP4MCP23X17GPIORegisters {
// A side
SP4_MCP23S17_IODIRA = 0x00,
SP4_MCP23S17_IPOLA = 0x02,
SP4_MCP23S17_GPINTENA = 0x04,
SP4_MCP23S17_DEFVALA = 0x06,
SP4_MCP23S17_INTCONA = 0x08,
SP4_MCP23S17_IOCONA = 0x0A,
SP4_MCP23S17_GPPUA = 0x0C,
SP4_MCP23S17_INTFA = 0x0E,
SP4_MCP23S17_INTCAPA = 0x10,
SP4_MCP23S17_GPIOA = 0x12,
SP4_MCP23S17_OLATA = 0x14,
// B side
SP4_MCP23S17_IODIRB = 0x01,
SP4_MCP23S17_IPOLB = 0x03,
SP4_MCP23S17_GPINTENB = 0x05,
SP4_MCP23S17_DEFVALB = 0x07,
SP4_MCP23S17_INTCONB = 0x09,
SP4_MCP23S17_IOCONB = 0x0B,
SP4_MCP23S17_GPPUB = 0x0D,
SP4_MCP23S17_INTFB = 0x0F,
SP4_MCP23S17_INTCAPB = 0x11,
SP4_MCP23S17_GPIOB = 0x13,
SP4_MCP23S17_OLATB = 0x15,
};
uint8_t sp4_mcp23s17_olata = 0;
uint8_t sp4_mcp23s17_olatb = 0;
void SP4Mcp23S17Enable(void) {
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
digitalWrite(SPro.pin_register_cs, 0);
}
void SP4Mcp23S17Disable(void) {
SPI.endTransaction();
digitalWrite(SPro.pin_register_cs, 1);
}
uint32_t SP4Mcp23S17Read16(uint8_t reg) {
// Read 16-bit registers: (regb << 8) | rega
SP4Mcp23S17Enable();
SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS | 1);
SPI.transfer(reg);
uint32_t value = SPI.transfer(0xFF); // RegA
value |= (SPI.transfer(0xFF) << 8); // RegB
SP4Mcp23S17Disable();
return value;
}
uint32_t SP4Mcp23S17Read(uint8_t reg) {
SP4Mcp23S17Enable();
SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS | 1);
SPI.transfer(reg);
uint32_t value = SPI.transfer(0xFF);
SP4Mcp23S17Disable();
return value;
}
void SP4Mcp23S17Write(uint8_t reg, uint8_t value) {
SP4Mcp23S17Enable();
SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS);
SPI.transfer(reg);
SPI.transfer(value);
SP4Mcp23S17Disable();
}
void SP4Mcp23S17Update(uint8_t pin, bool pin_value, uint8_t reg_addr) {
uint8_t bit = pin % 8;
uint8_t reg_value = 0;
if (reg_addr == SP4_MCP23S17_OLATA) {
reg_value = sp4_mcp23s17_olata;
} else if (reg_addr == SP4_MCP23S17_OLATB) {
reg_value = sp4_mcp23s17_olatb;
} else {
reg_value = SP4Mcp23S17Read(reg_addr);
}
if (pin_value) {
reg_value |= 1 << bit;
} else {
reg_value &= ~(1 << bit);
}
SP4Mcp23S17Write(reg_addr, reg_value);
if (reg_addr == SP4_MCP23S17_OLATA) {
sp4_mcp23s17_olata = reg_value;
} else if (reg_addr == SP4_MCP23S17_OLATB) {
sp4_mcp23s17_olatb = reg_value;
}
}
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;
if (flags == INPUT) {
SP4Mcp23S17Update(pin, true, iodir);
SP4Mcp23S17Update(pin, false, gppu);
} else if (flags == (INPUT | PULLUP)) {
SP4Mcp23S17Update(pin, true, iodir);
SP4Mcp23S17Update(pin, true, gppu);
} else if (flags == OUTPUT) {
SP4Mcp23S17Update(pin, false, iodir);
}
}
bool SP4Mcp23S17DigitalRead(uint8_t pin) {
uint8_t bit = pin % 8;
uint8_t reg_addr = pin < 8 ? SP4_MCP23S17_GPIOA : SP4_MCP23S17_GPIOB;
uint8_t value = SP4Mcp23S17Read(reg_addr);
return value & (1 << bit);
}
void SP4Mcp23S17DigitalWrite(uint8_t pin, bool value) {
uint8_t reg_addr = pin < 8 ? SP4_MCP23S17_OLATA : SP4_MCP23S17_OLATB;
SP4Mcp23S17Update(pin, value, reg_addr);
}
/*********************************************************************************************\
* Shelly Pro 4
\*********************************************************************************************/
const uint8_t sp4_relay_pin[] = { 8, 13, 14, 12 };
const uint8_t sp4_switch_pin[] = { 6, 1, 0, 15 };
const uint8_t sp4_button_pin[] = { 5, 2, 3 };
void ShellyPro4Init(void) {
/*
Shelly Pro 4PM MCP23S17 registers
bit 0 = input, inverted - Switch3
bit 1 = input, inverted - Switch2
bit 2 = input - Button Down
bit 3 = input - Button OK
bit 4 = output - Reset, display, ADE7953
bit 5 = input - Button Up
bit 6 = input, inverted - Switch1
bit 7
bit 8 = output - Relay O1
bit 9
bit 10
bit 11
bit 12 = output - Relay O4
bit 13 = output - Relay O2
bit 14 = output - Relay O3
bit 15 = input, inverted - Switch4
*/
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
sp4_mcp23s17_olata = SP4Mcp23S17Read(SP4_MCP23S17_OLATA);
sp4_mcp23s17_olatb = SP4Mcp23S17Read(SP4_MCP23S17_OLATB);
SP4Mcp23S17PinMode(4, OUTPUT); // Reset display, ADE7943
SP4Mcp23S17DigitalWrite(4, 1);
for (uint32_t i = 0; i < 3; i++) {
SP4Mcp23S17PinMode(sp4_button_pin[i], INPUT); // Button Up, Down, OK (RC with 10k to 3V3 and button shorting C)
}
SPro.button_offset = -1;
for (uint32_t i = 0; i < 4; i++) {
SP4Mcp23S17PinMode(sp4_switch_pin[i], INPUT); // Switch1..4
SP4Mcp23S17PinMode(sp4_relay_pin[i], OUTPUT); // Relay O1..O4
}
SPro.switch_offset = -1;
// Read current input register state
SPro.input_state = SP4Mcp23S17Read16(SP4_MCP23S17_GPIOA) & 0x806F; // Read gpio and clear interrupt
attachInterrupt(SPro.pin_mcp23s17_int, ShellyProUpdateIsr, CHANGE);
}
void ShellyPro4Reset(void) {
SP4Mcp23S17DigitalWrite(4, 0); // Reset pin display, ADE7953
delay(1); // To initiate a hardware reset, this pin must be brought low for a minimum of 10 μs.
SP4Mcp23S17DigitalWrite(4, 1);
}
bool ShellyProAddButton(void) {
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; } // Support three buttons
uint32_t state = bitRead(SPro.input_state, sp4_button_pin[index]); // 1 on power on and restart
XdrvMailbox.index = state;
return true;
}
bool ShellyProAddSwitch(void) {
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; } // Support four switches
uint32_t state = bitRead(SPro.input_state, sp4_switch_pin[index]); // 0 on power on and restart
XdrvMailbox.index = state ^1; // Invert
return true;
}
void ShellyProUpdateIsr(void) {
/*
The goal if this function is to minimize SPI and SetVirtualPinState calls
*/
uint32_t input_state = SP4Mcp23S17Read16(SP4_MCP23S17_INTCAPA); // Read intcap and clear interrupt
input_state &= 0x806F; // Only test input bits
// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Input from %04X to %04X"), SPro.input_state, input_state);
if (TasmotaGlobal.uptime < 3) { return; } // Flush interrupt for 3 seconds after poweron
uint32_t mask = 1;
for (uint32_t j = 0; j < 16; j++) {
if ((input_state & mask) != (SPro.input_state & mask)) {
uint32_t state = (input_state >> j) &1;
// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Change pin %d to %d"), j, state);
for (uint32_t i = 0; i < 4; i++) {
if (j == sp4_switch_pin[i]) {
SwitchSetVirtualPinState(SPro.switch_offset +i, state ^1); // Invert
}
else if ((i < 3) && (j == sp4_button_pin[i])) {
ButtonSetVirtualPinState(SPro.button_offset +i, state);
}
}
}
mask <<= 1;
}
SPro.input_state = input_state;
}
bool ShellyProButton(void) {
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; } // Only support Up, Down, Ok
uint32_t button = XdrvMailbox.payload;
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);
// Do something with the Up,Down,Ok button
switch (button_index) {
case 0: // Up
break;
case 1: // Down
break;
case 2: // Ok
break;
}
}
return true; // Disable further button processing
}
/*********************************************************************************************\
* Shelly Pro 1/2
\*********************************************************************************************/
void ShellyProUpdate(void) { void ShellyProUpdate(void) {
// Shelly Pro 595 register /*
// bit 0 = relay/led 1 Shelly Pro 1/2/PM 74HC595 register
// bit 1 = relay/led 2 bit 0 = relay/led 1
// bit 2 = wifi led blue bit 1 = relay/led 2
// bit 3 = wifi led green bit 2 = wifi led blue
// bit 4 = wifi led red bit 3 = wifi led green
// bit 5 - 7 = nc bit 4 = wifi led red
// OE is connected to Gnd with 470 ohm resistor R62 AND a capacitor C81 to 3V3 bit 5 - 7 = nc
// - this inhibits output of signals (also relay state) during power on for a few seconds OE is connected to Gnd with 470 ohm resistor R62 AND a capacitor C81 to 3V3
- this inhibits output of signals (also relay state) during power on for a few seconds
*/
uint8_t val = SPro.power | SPro.ledlink; uint8_t val = SPro.power | SPro.ledlink;
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
SPI.transfer(val); // Write 74HC595 shift register SPI.transfer(val); // Write 74HC595 shift register
SPI.endTransaction(); SPI.endTransaction();
// delayMicroseconds(2); // Wait for SPI clock to stop // delayMicroseconds(2); // Wait for SPI clock to stop
digitalWrite(SPro.pin_shift595_rclk, 1); // Latch data digitalWrite(SPro.pin_register_cs, 1); // Latch data
delayMicroseconds(1); // Shelly 10mS delayMicroseconds(1); // Shelly 10mS
digitalWrite(SPro.pin_shift595_rclk, 0); digitalWrite(SPro.pin_register_cs, 0);
} }
/*********************************************************************************************\
* Shelly Pro
\*********************************************************************************************/
void ShellyProPreInit(void) { void ShellyProPreInit(void) {
if ((SPI_MOSI_MISO == TasmotaGlobal.spi_enabled) && if ((SPI_MOSI_MISO == TasmotaGlobal.spi_enabled) &&
PinUsed(GPIO_SPI_CS) && PinUsed(GPIO_SPI_CS) && // 74HC595 rclk / MCP23S17
TasmotaGlobal.gpio_optiona.shelly_pro) { // Option_A7 TasmotaGlobal.gpio_optiona.shelly_pro) { // Option_A7
if (PinUsed(GPIO_SWT1) || PinUsed(GPIO_KEY1)) { if (PinUsed(GPIO_SWT1) || PinUsed(GPIO_KEY1)) {
TasmotaGlobal.devices_present++; // Shelly Pro 1 SPro.detected = 1; // Shelly Pro 1
if (PinUsed(GPIO_SWT1, 1) || PinUsed(GPIO_KEY1, 1)) { if (PinUsed(GPIO_SWT1, 1) || PinUsed(GPIO_KEY1, 1)) {
TasmotaGlobal.devices_present++; // Shelly Pro 2 SPro.detected = 2; // Shelly Pro 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.pin_shift595_rclk = Pin(GPIO_SPI_CS); if (SPro.detected) {
digitalWrite(SPro.pin_shift595_rclk, 0); TasmotaGlobal.devices_present += SPro.detected;
pinMode(SPro.pin_shift595_rclk, OUTPUT);
SPro.pin_register_cs = Pin(GPIO_SPI_CS);
digitalWrite(SPro.pin_register_cs, (4 == SPro.detected) ? 1 : 0); // Prep 74HC595 rclk
pinMode(SPro.pin_register_cs, OUTPUT);
// Does nothing if SPI is already initiated (by ADE7953) so no harm done // Does nothing if SPI is already initiated (by ADE7953) so no harm done
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);
SPro.ledlink = 0x18; // Blue led on - set by first call ShellyProPower() if (4 == SPro.detected) {
SPro.detected = true; SPro.pin_mcp23s17_int = SHELLY_PRO_4_PIN_MCP23S17_INT; // GPIO35 = MCP23S17 common interrupt
pinMode(SPro.pin_mcp23s17_int, INPUT);
ShellyPro4Init(); // Init MCP23S17
}
} }
} }
} }
void ShellyProInit(void) { void ShellyProInit(void) {
int pin_lan_reset = 5; // GPIO5 = LAN8720 nRST 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); digitalWrite(pin_lan_reset, 0);
pinMode(pin_lan_reset, OUTPUT); 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); digitalWrite(pin_lan_reset, 1);
AddLog(LOG_LEVEL_INFO, PSTR("HDW: Shelly Pro %d%s initialized"), AddLog(LOG_LEVEL_INFO, PSTR("HDW: Shelly Pro %d%s initialized"),
TasmotaGlobal.devices_present, (PinUsed(GPIO_ADE7953_CS))?"PM":""); SPro.detected, (PinUsed(GPIO_ADE7953_CS))?"PM":"");
SPro.init_done = true;
} }
void ShellyProPower(void) { void ShellyProPower(void) {
SPro.power = XdrvMailbox.index &3; if (SPro.detected != 4) {
ShellyProUpdate(); SPro.power = XdrvMailbox.index &3;
ShellyProUpdate();
} else {
// 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
}
}
} }
void ShellyProUpdateLedLink(uint32_t ledlink) { void ShellyProUpdateLedLink(uint32_t ledlink) {
@ -109,37 +416,42 @@ void ShellyProUpdateLedLink(uint32_t ledlink) {
} }
void ShellyProLedLink(void) { void ShellyProLedLink(void) {
/* if (!SPro.init_done) { return; } // Block write before first power update
bit 2 = blue, 3 = green, 4 = red if (SPro.detected != 4) {
Shelly Pro documentation /*
- Blue light indicator will be on if in AP mode. bit 2 = blue, 3 = green, 4 = red
- Red light indicator will be on if in STA mode and not connected to a Wi-Fi network. Shelly Pro documentation
- Yellow light indicator will be on if in STA mode and connected to a Wi-Fi network. - Blue light indicator will be on if in AP mode.
- Green light indicator will be on if in STA mode and connected to a Wi-Fi network and to the Shelly Cloud. - Red light indicator will be on if in STA mode and not connected to a Wi-Fi network.
- The light indicator will be flashing Red/Blue if OTA update is in progress. - Yellow light indicator will be on if in STA mode and connected to a Wi-Fi network.
Tasmota behaviour - Green light indicator will be on if in STA mode and connected to a Wi-Fi network and to the Shelly Cloud.
- Blue light indicator will blink if no wifi or mqtt. - The light indicator will be flashing Red/Blue if OTA update is in progress.
- Green light indicator will be on if in STA mode and connected to a Wi-Fi network. Tasmota behaviour
*/ - Blue light indicator will blink if no wifi or mqtt.
SPro.last_update = TasmotaGlobal.uptime; - Green light indicator will be on if in STA mode and connected to a Wi-Fi network.
uint32_t ledlink = 0x1C; // All leds off */
if (XdrvMailbox.index) { SPro.last_update = TasmotaGlobal.uptime;
ledlink &= 0xFB; // Blue blinks if wifi/mqtt lost uint32_t ledlink = 0x1C; // All leds off
if (XdrvMailbox.index) {
ledlink &= 0xFB; // Blue blinks if wifi/mqtt lost
}
else if (!TasmotaGlobal.global_state.wifi_down) {
ledlink &= 0xF7; // Green On
}
ShellyProUpdateLedLink(ledlink);
} }
else if (!TasmotaGlobal.global_state.wifi_down) {
ledlink &= 0xF7; // Green On
}
ShellyProUpdateLedLink(ledlink);
} }
void ShellyProLedLinkWifiOff(void) { void ShellyProLedLinkWifiOff(void) {
/* if (!SPro.init_done) { return; }
bit 2 = blue, 3 = green, 4 = red if (SPro.detected != 4) {
- Green light indicator will be on if in STA mode and connected to a Wi-Fi network. /*
*/ bit 2 = blue, 3 = green, 4 = red
if (SPro.last_update +1 < TasmotaGlobal.uptime) { - Green light indicator will be on if in STA mode and connected to a Wi-Fi network.
ShellyProUpdateLedLink((TasmotaGlobal.global_state.wifi_down) ? 0x1C : 0x14); // Green off if wifi OFF */
if (SPro.last_update +1 < TasmotaGlobal.uptime) {
ShellyProUpdateLedLink((TasmotaGlobal.global_state.wifi_down) ? 0x1C : 0x14); // Green off if wifi OFF
}
} }
} }
@ -150,22 +462,33 @@ void ShellyProLedLinkWifiOff(void) {
bool Xdrv88(uint32_t function) { bool Xdrv88(uint32_t function) {
bool result = false; bool result = false;
if (FUNC_PRE_INIT == function) { if (FUNC_MODULE_INIT == function) {
ShellyProPreInit(); ShellyProPreInit();
} else if (SPro.detected) { } else if (SPro.detected) {
switch (function) { switch (function) {
/*
case FUNC_BUTTON_PRESSED:
result = ShellyProButton();
break;
*/
case FUNC_EVERY_SECOND: case FUNC_EVERY_SECOND:
ShellyProLedLinkWifiOff(); ShellyProLedLinkWifiOff();
break; break;
case FUNC_SET_POWER: case FUNC_SET_POWER:
ShellyProPower(); ShellyProPower();
break; break;
case FUNC_LED_LINK:
ShellyProLedLink();
break;
case FUNC_INIT: case FUNC_INIT:
ShellyProInit(); ShellyProInit();
break; break;
case FUNC_ADD_BUTTON:
result = ShellyProAddButton();
break;
case FUNC_ADD_SWITCH:
result = ShellyProAddSwitch();
break;
case FUNC_LED_LINK:
ShellyProLedLink();
break;
} }
} }
return result; return result;

View File

@ -1,498 +0,0 @@
/*
xdrv_88_shelly_pro.ino - Shelly pro family support for Tasmota
Copyright (C) 2022 Theo Arends
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef ESP32
#ifdef USE_SPI
#ifdef USE_SHELLY_PRO
/*********************************************************************************************\
* Shelly Pro support
*
* {"NAME":"Shelly Pro 1","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"}
* {"NAME":"Shelly Pro 1PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3459,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"}
* {"NAME":"Shelly Pro 2","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350;AdcParam2 2,5600,4700,3350"}
* {"NAME":"Shelly Pro 2PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,9569,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3460,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350;AdcParam2 2,5600,4700,3350"}
* {"NAME":"Shelly Pro 4PM","GPIO":[0,6210,0,6214,9568,0,0,0,0,0,9569,0,768,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,736,704,3461,0,4736,0,0,672],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"}
*
* Shelly Pro 1/2 uses SPI to control one 74HC595 for relays/leds and one ADE7953 (1PM) or two ADE7953 (2PM) for energy monitoring
* Shelly Pro 4 uses an SPI to control one MCP23S17 for buttons/switches/relays/leds and two ADE7953 for energy monitoring and a second SPI for the display
\*********************************************************************************************/
#define XDRV_88 88
#define SHELLY_PRO_PIN_LAN8720_RESET 5
#define SHELLY_PRO_4_PIN_SPI_CS 16
#define SHELLY_PRO_4_PIN_MCP23S17_INT 35
#define SHELLY_PRO_4_MCP23S17_ADDRESS 0x40
struct SPro {
uint32_t last_update;
uint16_t input_state;
int8_t switch_offset;
int8_t button_offset;
uint8_t pin_register_cs;
uint8_t pin_mcp23s17_int;
uint8_t ledlink;
uint8_t power;
bool init_done;
uint8_t detected;
} SPro;
/*********************************************************************************************\
* Shelly Pro MCP23S17 support
\*********************************************************************************************/
enum SP4MCP23X17GPIORegisters {
// A side
SP4_MCP23S17_IODIRA = 0x00,
SP4_MCP23S17_IPOLA = 0x02,
SP4_MCP23S17_GPINTENA = 0x04,
SP4_MCP23S17_DEFVALA = 0x06,
SP4_MCP23S17_INTCONA = 0x08,
SP4_MCP23S17_IOCONA = 0x0A,
SP4_MCP23S17_GPPUA = 0x0C,
SP4_MCP23S17_INTFA = 0x0E,
SP4_MCP23S17_INTCAPA = 0x10,
SP4_MCP23S17_GPIOA = 0x12,
SP4_MCP23S17_OLATA = 0x14,
// B side
SP4_MCP23S17_IODIRB = 0x01,
SP4_MCP23S17_IPOLB = 0x03,
SP4_MCP23S17_GPINTENB = 0x05,
SP4_MCP23S17_DEFVALB = 0x07,
SP4_MCP23S17_INTCONB = 0x09,
SP4_MCP23S17_IOCONB = 0x0B,
SP4_MCP23S17_GPPUB = 0x0D,
SP4_MCP23S17_INTFB = 0x0F,
SP4_MCP23S17_INTCAPB = 0x11,
SP4_MCP23S17_GPIOB = 0x13,
SP4_MCP23S17_OLATB = 0x15,
};
uint8_t sp4_mcp23s17_olata = 0;
uint8_t sp4_mcp23s17_olatb = 0;
void SP4Mcp23S17Enable(void) {
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
digitalWrite(SPro.pin_register_cs, 0);
}
void SP4Mcp23S17Disable(void) {
SPI.endTransaction();
digitalWrite(SPro.pin_register_cs, 1);
}
uint32_t SP4Mcp23S17Read16(uint8_t reg) {
// Read 16-bit registers: (regb << 8) | rega
SP4Mcp23S17Enable();
SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS | 1);
SPI.transfer(reg);
uint32_t value = SPI.transfer(0xFF); // RegA
value |= (SPI.transfer(0xFF) << 8); // RegB
SP4Mcp23S17Disable();
return value;
}
uint32_t SP4Mcp23S17Read(uint8_t reg) {
SP4Mcp23S17Enable();
SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS | 1);
SPI.transfer(reg);
uint32_t value = SPI.transfer(0xFF);
SP4Mcp23S17Disable();
return value;
}
void SP4Mcp23S17Write(uint8_t reg, uint8_t value) {
SP4Mcp23S17Enable();
SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS);
SPI.transfer(reg);
SPI.transfer(value);
SP4Mcp23S17Disable();
}
void SP4Mcp23S17Update(uint8_t pin, bool pin_value, uint8_t reg_addr) {
uint8_t bit = pin % 8;
uint8_t reg_value = 0;
if (reg_addr == SP4_MCP23S17_OLATA) {
reg_value = sp4_mcp23s17_olata;
} else if (reg_addr == SP4_MCP23S17_OLATB) {
reg_value = sp4_mcp23s17_olatb;
} else {
reg_value = SP4Mcp23S17Read(reg_addr);
}
if (pin_value) {
reg_value |= 1 << bit;
} else {
reg_value &= ~(1 << bit);
}
SP4Mcp23S17Write(reg_addr, reg_value);
if (reg_addr == SP4_MCP23S17_OLATA) {
sp4_mcp23s17_olata = reg_value;
} else if (reg_addr == SP4_MCP23S17_OLATB) {
sp4_mcp23s17_olatb = reg_value;
}
}
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;
if (flags == INPUT) {
SP4Mcp23S17Update(pin, true, iodir);
SP4Mcp23S17Update(pin, false, gppu);
} else if (flags == (INPUT | PULLUP)) {
SP4Mcp23S17Update(pin, true, iodir);
SP4Mcp23S17Update(pin, true, gppu);
} else if (flags == OUTPUT) {
SP4Mcp23S17Update(pin, false, iodir);
}
}
bool SP4Mcp23S17DigitalRead(uint8_t pin) {
uint8_t bit = pin % 8;
uint8_t reg_addr = pin < 8 ? SP4_MCP23S17_GPIOA : SP4_MCP23S17_GPIOB;
uint8_t value = SP4Mcp23S17Read(reg_addr);
return value & (1 << bit);
}
void SP4Mcp23S17DigitalWrite(uint8_t pin, bool value) {
uint8_t reg_addr = pin < 8 ? SP4_MCP23S17_OLATA : SP4_MCP23S17_OLATB;
SP4Mcp23S17Update(pin, value, reg_addr);
}
/*********************************************************************************************\
* Shelly Pro 4
\*********************************************************************************************/
const uint8_t sp4_relay_pin[] = { 8, 13, 14, 12 };
const uint8_t sp4_switch_pin[] = { 6, 1, 0, 15 };
const uint8_t sp4_button_pin[] = { 5, 2, 3 };
void ShellyPro4Init(void) {
/*
Shelly Pro 4PM MCP23S17 registers
bit 0 = input, inverted - Switch3
bit 1 = input, inverted - Switch2
bit 2 = input - Button Down
bit 3 = input - Button OK
bit 4 = output - Reset, display, ADE7953
bit 5 = input - Button Up
bit 6 = input, inverted - Switch1
bit 7
bit 8 = output - Relay O1
bit 9
bit 10
bit 11
bit 12 = output - Relay O4
bit 13 = output - Relay O2
bit 14 = output - Relay O3
bit 15 = input, inverted - Switch4
*/
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
sp4_mcp23s17_olata = SP4Mcp23S17Read(SP4_MCP23S17_OLATA);
sp4_mcp23s17_olatb = SP4Mcp23S17Read(SP4_MCP23S17_OLATB);
SP4Mcp23S17PinMode(4, OUTPUT); // Reset display, ADE7943
SP4Mcp23S17DigitalWrite(4, 1);
for (uint32_t i = 0; i < 3; i++) {
SP4Mcp23S17PinMode(sp4_button_pin[i], INPUT); // Button Up, Down, OK (RC with 10k to 3V3 and button shorting C)
}
SPro.button_offset = -1;
for (uint32_t i = 0; i < 4; i++) {
SP4Mcp23S17PinMode(sp4_switch_pin[i], INPUT); // Switch1..4
SP4Mcp23S17PinMode(sp4_relay_pin[i], OUTPUT); // Relay O1..O4
}
SPro.switch_offset = -1;
// Read current input register state
SPro.input_state = SP4Mcp23S17Read16(SP4_MCP23S17_GPIOA) & 0x806F; // Read gpio and clear interrupt
attachInterrupt(SPro.pin_mcp23s17_int, ShellyProUpdateIsr, CHANGE);
}
void ShellyPro4Reset(void) {
SP4Mcp23S17DigitalWrite(4, 0); // Reset pin display, ADE7953
delay(1); // To initiate a hardware reset, this pin must be brought low for a minimum of 10 μs.
SP4Mcp23S17DigitalWrite(4, 1);
}
bool ShellyProAddButton(void) {
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; } // Support three buttons
uint32_t state = bitRead(SPro.input_state, sp4_button_pin[index]); // 1 on power on and restart
XdrvMailbox.index = state;
return true;
}
bool ShellyProAddSwitch(void) {
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; } // Support four switches
uint32_t state = bitRead(SPro.input_state, sp4_switch_pin[index]); // 0 on power on and restart
XdrvMailbox.index = state ^1; // Invert
return true;
}
void ShellyProUpdateIsr(void) {
/*
The goal if this function is to minimize SPI and SetVirtualPinState calls
*/
uint32_t input_state = SP4Mcp23S17Read16(SP4_MCP23S17_INTCAPA); // Read intcap and clear interrupt
input_state &= 0x806F; // Only test input bits
// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Input from %04X to %04X"), SPro.input_state, input_state);
if (TasmotaGlobal.uptime < 3) { return; } // Flush interrupt for 3 seconds after poweron
uint32_t mask = 1;
for (uint32_t j = 0; j < 16; j++) {
if ((input_state & mask) != (SPro.input_state & mask)) {
uint32_t state = (input_state >> j) &1;
// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Change pin %d to %d"), j, state);
for (uint32_t i = 0; i < 4; i++) {
if (j == sp4_switch_pin[i]) {
SwitchSetVirtualPinState(SPro.switch_offset +i, state ^1); // Invert
}
else if ((i < 3) && (j == sp4_button_pin[i])) {
ButtonSetVirtualPinState(SPro.button_offset +i, state);
}
}
}
mask <<= 1;
}
SPro.input_state = input_state;
}
bool ShellyProButton(void) {
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; } // Only support Up, Down, Ok
uint32_t button = XdrvMailbox.payload;
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);
// Do something with the Up,Down,Ok button
switch (button_index) {
case 0: // Up
break;
case 1: // Down
break;
case 2: // Ok
break;
}
}
return true; // Disable further button processing
}
/*********************************************************************************************\
* Shelly Pro 1/2
\*********************************************************************************************/
void ShellyProUpdate(void) {
/*
Shelly Pro 1/2/PM 74HC595 register
bit 0 = relay/led 1
bit 1 = relay/led 2
bit 2 = wifi led blue
bit 3 = wifi led green
bit 4 = wifi led red
bit 5 - 7 = nc
OE is connected to Gnd with 470 ohm resistor R62 AND a capacitor C81 to 3V3
- this inhibits output of signals (also relay state) during power on for a few seconds
*/
uint8_t val = SPro.power | SPro.ledlink;
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
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
digitalWrite(SPro.pin_register_cs, 0);
}
/*********************************************************************************************\
* Shelly Pro
\*********************************************************************************************/
void ShellyProPreInit(void) {
if ((SPI_MOSI_MISO == TasmotaGlobal.spi_enabled) &&
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
if (PinUsed(GPIO_SWT1, 1) || PinUsed(GPIO_KEY1, 1)) {
SPro.detected = 2; // Shelly Pro 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)
}
if (SPro.detected) {
TasmotaGlobal.devices_present += SPro.detected;
SPro.pin_register_cs = Pin(GPIO_SPI_CS);
digitalWrite(SPro.pin_register_cs, (4 == SPro.detected) ? 1 : 0); // Prep 74HC595 rclk
pinMode(SPro.pin_register_cs, OUTPUT);
// Does nothing if SPI is already initiated (by ADE7953) so no harm done
SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1);
if (4 == SPro.detected) {
SPro.pin_mcp23s17_int = SHELLY_PRO_4_PIN_MCP23S17_INT; // GPIO35 = MCP23S17 common interrupt
pinMode(SPro.pin_mcp23s17_int, INPUT);
ShellyPro4Init(); // Init MCP23S17
}
}
}
}
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
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
digitalWrite(pin_lan_reset, 1);
AddLog(LOG_LEVEL_INFO, PSTR("HDW: Shelly Pro %d%s initialized"),
SPro.detected, (PinUsed(GPIO_ADE7953_CS))?"PM":"");
SPro.init_done = true;
}
void ShellyProPower(void) {
if (SPro.detected != 4) {
SPro.power = XdrvMailbox.index &3;
ShellyProUpdate();
} else {
// 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
}
}
}
void ShellyProUpdateLedLink(uint32_t ledlink) {
if (ledlink != SPro.ledlink) {
SPro.ledlink = ledlink;
ShellyProUpdate();
}
}
void ShellyProLedLink(void) {
if (!SPro.init_done) { return; } // Block write before first power update
if (SPro.detected != 4) {
/*
bit 2 = blue, 3 = green, 4 = red
Shelly Pro documentation
- Blue light indicator will be on if in AP mode.
- Red light indicator will be on if in STA mode and not connected to a Wi-Fi network.
- Yellow light indicator will be on if in STA mode and connected to a Wi-Fi network.
- Green light indicator will be on if in STA mode and connected to a Wi-Fi network and to the Shelly Cloud.
- The light indicator will be flashing Red/Blue if OTA update is in progress.
Tasmota behaviour
- Blue light indicator will blink if no wifi or mqtt.
- 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
if (XdrvMailbox.index) {
ledlink &= 0xFB; // Blue blinks if wifi/mqtt lost
}
else if (!TasmotaGlobal.global_state.wifi_down) {
ledlink &= 0xF7; // Green On
}
ShellyProUpdateLedLink(ledlink);
}
}
void ShellyProLedLinkWifiOff(void) {
if (!SPro.init_done) { return; }
if (SPro.detected != 4) {
/*
bit 2 = blue, 3 = green, 4 = red
- Green light indicator will be on if in STA mode and connected to a Wi-Fi network.
*/
if (SPro.last_update +1 < TasmotaGlobal.uptime) {
ShellyProUpdateLedLink((TasmotaGlobal.global_state.wifi_down) ? 0x1C : 0x14); // Green off if wifi OFF
}
}
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
bool Xdrv88(uint32_t function) {
bool result = false;
if (FUNC_MODULE_INIT == function) {
ShellyProPreInit();
} else if (SPro.detected) {
switch (function) {
/*
case FUNC_BUTTON_PRESSED:
result = ShellyProButton();
break;
*/
case FUNC_EVERY_SECOND:
ShellyProLedLinkWifiOff();
break;
case FUNC_SET_POWER:
ShellyProPower();
break;
case FUNC_INIT:
ShellyProInit();
break;
case FUNC_ADD_BUTTON:
result = ShellyProAddButton();
break;
case FUNC_ADD_SWITCH:
result = ShellyProAddSwitch();
break;
case FUNC_LED_LINK:
ShellyProLedLink();
break;
}
}
return result;
}
#endif // USE_SHELLY_PRO
#endif // USE_SPI
#endif // ESP32

View File

@ -1,15 +1,7 @@
/* /*
xnrg_24_biopdu.ino - BioPDU-625x12 (based on xnrg_05_pzem_ac.ino) xnrg_24_biopdu.ino - BioPDU-625x12 (based on xnrg_05_pzem_ac.ino)
Biomine 625x12 Custom Board
6 x 25A Relays
6 x Independent PZEM-004V3 Modbus AC energy sensor
3bit serial switch
Integrated MCP23008
Template {"NAME":"Olimex ESP32-PoE-BioPDU","GPIO":[1,10209,10210,1,10144,1,0,0,5536,640,1,1,608,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,1,10208,1,1,10176,0,0,1],"FLAG":0,"BASE":1} Copyright (C) 2023 Fabrizio Amodio
Copyright (C) 2021 Theo Arends
Copyright (C) 2022-2023 Fabrizio Amodio
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -27,8 +19,15 @@
#if defined(USE_ENERGY_SENSOR_ESP32) && defined(USE_I2C) #if defined(USE_ENERGY_SENSOR_ESP32) && defined(USE_I2C)
#ifdef USE_BIOPDU #ifdef USE_BIOPDU
/*********************************************************************************************\
Biomine 625x12 Custom Board
6 x 25A Relays
6 x Independent PZEM-004V3 Modbus AC energy sensor
3bit serial switch
Integrated MCP23008
Template {"NAME":"Olimex ESP32-PoE-BioPDU","GPIO":[1,10209,10210,1,10144,1,0,0,5536,640,1,1,608,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,1,10208,1,1,10176,0,0,1],"FLAG":0,"BASE":1}
/*
BioPDU 625x12 Factory Settings: BioPDU 625x12 Factory Settings:
Template {"NAME":"Olimex ESP32-PoE-BioPDU","GPIO":[1,10209,10210,1,10144,1,0,0,5536,640,1,1,608,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,1,10208,1,1,10176,0,0,1],"FLAG":0,"BASE":1} Template {"NAME":"Olimex ESP32-PoE-BioPDU","GPIO":[1,10209,10210,1,10144,1,0,0,5536,640,1,1,608,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,1,10208,1,1,10176,0,0,1],"FLAG":0,"BASE":1}
@ -62,7 +61,7 @@
USE_MCP230xx_ADDR=0x20 USE_MCP230xx_ADDR=0x20
USE_MCP230xx_OUTPUT USE_MCP230xx_OUTPUT
USE_BIOPDU USE_BIOPDU
*/ \*********************************************************************************************/
#define XNRG_24 24 #define XNRG_24 24

View File

@ -206,7 +206,8 @@ a_setoption = [[
"(Light) start DMX ArtNet at boot, listen to UDP port as soon as network is up", "(Light) start DMX ArtNet at boot, listen to UDP port as soon as network is up",
"(Wifi) prefer IPv6 DNS resolution to IPv4 address when available. Requires `#define USE_IPV6`", "(Wifi) prefer IPv6 DNS resolution to IPv4 address when available. Requires `#define USE_IPV6`",
"(Energy) Force no voltage/frequency common", "(Energy) Force no voltage/frequency common",
"","","", "(Matter) Enable Matter protocol over Wifi",
"","",
"","","","", "","","","",
"","","","", "","","","",
"","","","", "","","","",
@ -292,7 +293,7 @@ a_features = [[
"USE_MODBUS_ENERGY","USE_SHELLY_PRO","USE_DALI","USE_BP1658CJ", "USE_MODBUS_ENERGY","USE_SHELLY_PRO","USE_DALI","USE_BP1658CJ",
"USE_DINGTIAN_RELAY","USE_HMC5883L","USE_LD2410","USE_ME007", "USE_DINGTIAN_RELAY","USE_HMC5883L","USE_LD2410","USE_ME007",
"USE_DISPLAY_TM1650","USE_PCA9632","USE_TUYAMCUBR","USE_SEN5X", "USE_DISPLAY_TM1650","USE_PCA9632","USE_TUYAMCUBR","USE_SEN5X",
"","","","", "USE_BIOPDU","","","",
"","","","", "","","","",
"","","","", "","","","",
"","","","" "","","",""
@ -323,7 +324,7 @@ else:
obj = json.load(fp) obj = json.load(fp)
def StartDecode(): def StartDecode():
print ("\n*** decode-status.py v12.3.1.5 by Theo Arends and Jacek Ziolkowski ***") print ("\n*** decode-status.py v12.3.1.6 by Theo Arends and Jacek Ziolkowski ***")
# print("Decoding\n{}".format(obj)) # print("Decoding\n{}".format(obj))