Open nurachese opened 1 year ago
Found a solution using @martgras modbus_number_write and template switches:
external_components:
- source:
type: git
url: https://github.com/martgras/esphome
#ref: modbus-fix
#ref: modbus-duplicate
#ref: modbus_controller
ref: modbus_number_write
components: [modbus_controller]
uart:
id: modbusio
tx_pin: GPIO17
rx_pin: GPIO5
baud_rate: 19200
stop_bits: 1
modbus:
#flow_control_pin: 5
id: modbus1
modbus_controller:
- id: moduloio1
## the Modbus device addr
address: 0x1
modbus_id: modbus1
setup_priority: -10
update_interval: 100ms
binary_sensor:
- platform: modbus_controller
modbus_controller_id: moduloio1
name: "Pulsanti luci ingresso"
id: Pulsanti_luci_ingresso
register_type: holding
address: 0xC0
bitmask: 1
#response_size: 2
- platform: modbus_controller
modbus_controller_id: moduloio1
name: "Pulsanti luci soggiorno"
id: Pulsanti_luci_soggiorno
register_type: holding
address: 0xC0
bitmask: 2
number:
- platform: modbus_controller
modbus_controller_id: moduloio1
id: Uscite_modulo1
name: "Uscite modulo1"
address: 0x70
value_type: U_WORD
lambda: "return x * 1.0; "
write_lambda: |-
ESP_LOGD("main","Modbus Number incoming value = %f",x);
uint16_t uscite1 = x ;
payload.push_back(uscite1);
return x * 1.0 ;
## multiply is ignored because lamdba is used
#multiply: 1.0
switch:
- platform: template
name: "Luce pulsanti luci ingresso/soggiorno/cucina"
id: Luce_pulsanti_luci_ingresso_soggiorno_cucina
lambda: |-
uint16_t UsciteM1 = id(Uscite_modulo1).state;
if (bitRead(UsciteM1,0)) {
return true;
} else {
return false;
}
turn_on_action:
- number.set:
id: Uscite_modulo1
value: !lambda |-
return id(Uscite_modulo1).state + 1;
turn_off_action:
- number.set:
id: Uscite_modulo1
value: !lambda |-
return id(Uscite_modulo1).state - 1;
- platform: template
name: "Luce pulsante balcone soggiorno"
id: Luce_pulsante_balcone_soggiorno
lambda: |-
uint16_t UsciteM1 = id(Uscite_modulo1).state;
if (bitRead(UsciteM1,1)) {
return true;
} else {
return false;
}
turn_on_action:
- number.set:
id: Uscite_modulo1
value: !lambda |-
return id(Uscite_modulo1).state + 2;
turn_off_action:
- number.set:
id: Uscite_modulo1
value: !lambda |-
return id(Uscite_modulo1).state - 2;
- platform: template
name: "Luce pulsante balcone camere"
id: Luce_pulsante_balcone_camere
lambda: |-
uint16_t UsciteM1 = id(Uscite_modulo1).state;
if (bitRead(UsciteM1,2)) {
return true;
} else {
return false;
}
turn_on_action:
- number.set:
id: Uscite_modulo1
value: !lambda |-
return id(Uscite_modulo1).state + 4;
turn_off_action:
- number.set:
id: Uscite_modulo1
value: !lambda |-
return id(Uscite_modulo1).state - 4;
I leave it open since the issue is still not solved.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Still not solved!
Still not solved!
Hi,guys. have you solved it? I meet the same problem. I've searched for a long time ,but don't find any solution. Writing the codes is difficult for me. it makes me really crazy
Look, how to implement registers like that in esphome with modbus controller? I would to read and write registers like 0x0032 and 0x0033, it is easy to read,but how to use switch component control the the 0x0032 and 0x0033 register, or write the registers correctly.
I also bumped into this problem, here is how I solved it. I used a modbus select as I wanted the interface to have some nice options to choose from
define a sensor to store the raw value to be used in the write lambda
- platform: modbus_controller
modbus_controller_id: ${modbus_controller}
id: my_charge_raw
register_type: holding
address: 111
value_type: U_WORD
Then I defined the select that would give the options to update the lower 2 bits of this register and retain the values
select:
- platform: modbus_controller
use_write_multiple: true
modbus_controller_id: ${modbus_controller}
name: "Charge option"
id: my_charge_option
address: 111
entity_category: config
value_type: U_WORD
optionsmap:
"None": 0
"Grid": 1
"Solar": 2
"Both Grid/Solar": 3
lambda: |-
// we are only interested in the 2 bits binary 0011 need to map the options 00 , 01 , 10 , 11 in select
//ESP_LOGE("main","Modbus Number incoming value = %d",x);
//ESP_LOGE("main","Modbus eval value = %d",(x & 0x0003));
if ((x & 0x0003) == 0)
return std::string("None");
if ((x & 0x0003) == 1)
return std::string("Grid");
if ((x & 0x0003) == 2)
return std::string("Solar");
if ((x & 0x0003) == 3)
return std::string("Both Grid/Solar");
return {};
write_lambda: |-
//ESP_LOGE("main","Modbus write gets = %d",value);
uint16_t unmodified = id(my_charge_raw).state;
//ESP_LOGE("main","Modbus write unmodified = %d", unmodified);
// optionsmap should only return 3 values... 00 , 01 , 11 so bitmask with complement 0x0003 to ensure we keep the original values in register. then appply or with the value that was chosen
uint16_t modified = ((unmodified & ~0x0003) | value);
//ESP_LOGE("main","Modbus write to write = %d", modified);
return modified;
I hope this snippet helps someone read/write the bits and keep the original register values
got it , thank you
The above solution by @tomatensaus worked for me. Thank you for sharing
I hope this snippet helps someone read/write the bits and keep the original register values
Thanks @tomatensaus super helpful and encouraging. I have two situations where bit mask really is paining me. And I have just slight issues with understanding your solution completely. You are using 0x0003 which is because you are manipulating bits 0 and 1 (for a two bit change). But what if im manipulating bits 4-5 in a 16 bit registry and want the rest to remain the same ? I realise of course the bit masks im adressen are 0x0030, but I have a hard time getting the read / write on it.
You would need to look at the 4th and 5th bit so 0x0003 changes to 0x30
- platform: modbus_controller
modbus_controller_id: ${modbus_controller}
id: my_charge_raw
register_type: holding
address: 178
value_type: U_WORD
select:
- platform: modbus_controller
use_write_multiple: true
modbus_controller_id: ${modbus_controller}
name: "Grid Peak Shaving"
id: esphome_select_grid_peak_shaving
address: 178
entity_category: config
value_type: U_WORD
optionsmap:
"Disabled": 16
"Enabled": 48
lambda: |-
if ((x & 0x30) == 16)
return std::string("Disabled");
if ((x & 0x30) == 48)
return std::string("Enabled");
return {};
write_lambda: |-
uint16_t unmodified = id(my_charge_raw).state;
uint16_t modified = ((unmodified & ~0x30) | value);
return modified;
4th and 5th should be 0x30 right ? (fourth = 10 and fifth = 20 ?)
Also, that code would report bits 0-5 correctly, but not 6-15 right ? Since the complementary operation only goes til 0x18 (or should be 0x30)
Sorry you are correct. I've updated the code. I was looking at the 3rd and 4th bit
Sorry you are correct. I've updated the code. I was looking at the 3rd and 4th bit
Perfect man, I didn't realise the write lambda would write the entire 16 bits and not just the part up to 5 bits! Cheers!
The problem
Hi all, I'm new in ESPhome, please be patient with me :-) I have an issue in Modbus Switch behaviour: I have a 16 inputs & 16 outputs modbus board, I configured the code with 16 Modbus Binary Sensors (perfectly working) and 16 Modbus Switches reading and writing on a 16 bit holding register (0x70). Each activation of any switch activates the right output but at the same time resets all other 15. It seems that the library is not taking into account the outputs state before sending the command.
Thank you in advance
Marcello
Which version of ESPHome has the issue?
2022.11.3
What type of installation are you using?
Home Assistant Add-on
Which version of Home Assistant has the issue?
2022.11.4
What platform are you using?
ESP32
Board
WirelessTag WT32-ETH01
Component causing the issue
Modbus Controller Switch
Example YAML snippet
Anything in the logs that might be useful for us?
Additional information
No response