Modbus fixes to work with pymodbus 1.3.1 (#8365)
* Fixed a bug where changing fan speed was not possible * Bump pymodbus version to 1.3.1 to fix issue #8285 * Changed all modbus components so that they use CONF_SLAVE from const.py * Fix checking result from a modbus transaction * Add missing decorator * Added modbus write coil service and added descriptions * Removed a hiding debug print
This commit is contained in:
parent
9bc5cd2d4b
commit
c48c2b00a8
5 changed files with 69 additions and 10 deletions
|
@ -49,6 +49,7 @@ class ModbusCoilSensor(BinarySensorDevice):
|
||||||
self._coil = int(coil)
|
self._coil = int(coil)
|
||||||
self._value = None
|
self._value = None
|
||||||
|
|
||||||
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
"""Return the name of the sensor."""
|
"""Return the name of the sensor."""
|
||||||
return self._name
|
return self._name
|
||||||
|
@ -61,4 +62,10 @@ class ModbusCoilSensor(BinarySensorDevice):
|
||||||
def update(self):
|
def update(self):
|
||||||
"""Update the state of the sensor."""
|
"""Update the state of the sensor."""
|
||||||
result = modbus.HUB.read_coils(self._slave, self._coil, 1)
|
result = modbus.HUB.read_coils(self._slave, self._coil, 1)
|
||||||
self._value = result.bits[0]
|
try:
|
||||||
|
self._value = result.bits[0]
|
||||||
|
except AttributeError:
|
||||||
|
_LOGGER.error(
|
||||||
|
'No response from modbus slave %s coil %s',
|
||||||
|
self._slave,
|
||||||
|
self._coil)
|
||||||
|
|
|
@ -6,13 +6,15 @@ https://home-assistant.io/components/modbus/
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
import threading
|
import threading
|
||||||
|
import os
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
from homeassistant.config import load_yaml_config_file
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP,
|
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP,
|
||||||
CONF_HOST, CONF_METHOD, CONF_PORT)
|
CONF_HOST, CONF_METHOD, CONF_PORT, ATTR_STATE)
|
||||||
|
|
||||||
DOMAIN = 'modbus'
|
DOMAIN = 'modbus'
|
||||||
|
|
||||||
|
@ -50,6 +52,7 @@ CONFIG_SCHEMA = vol.Schema({
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
SERVICE_WRITE_REGISTER = 'write_register'
|
SERVICE_WRITE_REGISTER = 'write_register'
|
||||||
|
SERVICE_WRITE_COIL = 'write_coil'
|
||||||
|
|
||||||
ATTR_ADDRESS = 'address'
|
ATTR_ADDRESS = 'address'
|
||||||
ATTR_UNIT = 'unit'
|
ATTR_UNIT = 'unit'
|
||||||
|
@ -61,6 +64,11 @@ SERVICE_WRITE_REGISTER_SCHEMA = vol.Schema({
|
||||||
vol.Required(ATTR_VALUE): vol.All(cv.ensure_list, [cv.positive_int])
|
vol.Required(ATTR_VALUE): vol.All(cv.ensure_list, [cv.positive_int])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
SERVICE_WRITE_COIL_SCHEMA = vol.Schema({
|
||||||
|
vol.Required(ATTR_UNIT): cv.positive_int,
|
||||||
|
vol.Required(ATTR_ADDRESS): cv.positive_int,
|
||||||
|
vol.Required(ATTR_STATE): cv.boolean
|
||||||
|
})
|
||||||
|
|
||||||
HUB = None
|
HUB = None
|
||||||
|
|
||||||
|
@ -105,9 +113,18 @@ def setup(hass, config):
|
||||||
HUB.connect()
|
HUB.connect()
|
||||||
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_modbus)
|
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_modbus)
|
||||||
|
|
||||||
|
descriptions = load_yaml_config_file(os.path.join(
|
||||||
|
os.path.dirname(__file__), 'services.yaml')).get(DOMAIN)
|
||||||
|
|
||||||
# Register services for modbus
|
# Register services for modbus
|
||||||
hass.services.register(DOMAIN, SERVICE_WRITE_REGISTER, write_register,
|
hass.services.register(
|
||||||
schema=SERVICE_WRITE_REGISTER_SCHEMA)
|
DOMAIN, SERVICE_WRITE_REGISTER, write_register,
|
||||||
|
descriptions.get(SERVICE_WRITE_REGISTER),
|
||||||
|
schema=SERVICE_WRITE_REGISTER_SCHEMA)
|
||||||
|
hass.services.register(
|
||||||
|
DOMAIN, SERVICE_WRITE_COIL, write_coil,
|
||||||
|
descriptions.get(SERVICE_WRITE_COIL),
|
||||||
|
schema=SERVICE_WRITE_COIL_SCHEMA)
|
||||||
|
|
||||||
def write_register(service):
|
def write_register(service):
|
||||||
"""Write modbus registers."""
|
"""Write modbus registers."""
|
||||||
|
@ -125,6 +142,13 @@ def setup(hass, config):
|
||||||
address,
|
address,
|
||||||
int(float(value)))
|
int(float(value)))
|
||||||
|
|
||||||
|
def write_coil(service):
|
||||||
|
"""Write modbus coil."""
|
||||||
|
unit = service.data.get(ATTR_UNIT)
|
||||||
|
address = service.data.get(ATTR_ADDRESS)
|
||||||
|
state = service.data.get(ATTR_STATE)
|
||||||
|
HUB.write_coil(unit, address, state)
|
||||||
|
|
||||||
hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_modbus)
|
hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_modbus)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -117,17 +117,20 @@ class ModbusRegisterSensor(Entity):
|
||||||
self._register,
|
self._register,
|
||||||
self._count)
|
self._count)
|
||||||
val = 0
|
val = 0
|
||||||
if not result:
|
|
||||||
|
try:
|
||||||
|
registers = result.registers
|
||||||
|
except AttributeError:
|
||||||
_LOGGER.error("No response from modbus slave %s register %s",
|
_LOGGER.error("No response from modbus slave %s register %s",
|
||||||
self._slave, self._register)
|
self._slave, self._register)
|
||||||
return
|
return
|
||||||
if self._data_type == DATA_TYPE_FLOAT:
|
if self._data_type == DATA_TYPE_FLOAT:
|
||||||
byte_string = b''.join(
|
byte_string = b''.join(
|
||||||
[x.to_bytes(2, byteorder='big') for x in result.registers]
|
[x.to_bytes(2, byteorder='big') for x in registers]
|
||||||
)
|
)
|
||||||
val = struct.unpack(">f", byte_string)[0]
|
val = struct.unpack(">f", byte_string)[0]
|
||||||
elif self._data_type == DATA_TYPE_INT:
|
elif self._data_type == DATA_TYPE_INT:
|
||||||
for i, res in enumerate(result.registers):
|
for i, res in enumerate(registers):
|
||||||
val += res * (2**(i*16))
|
val += res * (2**(i*16))
|
||||||
self._value = format(
|
self._value = format(
|
||||||
self._scale * val + self._offset, '.{}f'.format(self._precision))
|
self._scale * val + self._offset, '.{}f'.format(self._precision))
|
||||||
|
|
|
@ -483,3 +483,28 @@ apple_tv:
|
||||||
apple_tv_scan:
|
apple_tv_scan:
|
||||||
description: Scan for Apple TV devices.
|
description: Scan for Apple TV devices.
|
||||||
|
|
||||||
|
modbus:
|
||||||
|
write_register:
|
||||||
|
description: Write to a modbus holding register
|
||||||
|
fields:
|
||||||
|
unit:
|
||||||
|
description: Address of the modbus unit
|
||||||
|
example: 21
|
||||||
|
address:
|
||||||
|
description: Address of the holding register to write to
|
||||||
|
example: 0
|
||||||
|
value:
|
||||||
|
description: Value to write
|
||||||
|
example: 0
|
||||||
|
write_coil:
|
||||||
|
description: Write to a modbus coil
|
||||||
|
fields:
|
||||||
|
unit:
|
||||||
|
description: Address of the modbus unit
|
||||||
|
example: 21
|
||||||
|
address:
|
||||||
|
description: Address of the register to read
|
||||||
|
example: 0
|
||||||
|
state:
|
||||||
|
description: State to write
|
||||||
|
example: false
|
||||||
|
|
|
@ -70,10 +70,10 @@ class ModbusCoilSwitch(ToggleEntity):
|
||||||
def update(self):
|
def update(self):
|
||||||
"""Update the state of the switch."""
|
"""Update the state of the switch."""
|
||||||
result = modbus.HUB.read_coils(self._slave, self._coil, 1)
|
result = modbus.HUB.read_coils(self._slave, self._coil, 1)
|
||||||
if not result:
|
try:
|
||||||
|
self._is_on = bool(result.bits[0])
|
||||||
|
except AttributeError:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
'No response from modbus slave %s coil %s',
|
'No response from modbus slave %s coil %s',
|
||||||
self._slave,
|
self._slave,
|
||||||
self._coil)
|
self._coil)
|
||||||
return
|
|
||||||
self._is_on = bool(result.bits[0])
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue