I’m trying to modify the ADS component to be able to read and write PLC real values.
The reading of PLC values is working perfect, the writing to PLC poses a problem.
The write_to_ADS service only accepts integer values due to this line of code:
vol.Required(CONF_ADS_VALUE): vol.Coerce(int)
Now I want to modify this line so it also accepts float values.
If I currently provide a float value to the service, it typecasts this to an integer and the decimal digits are dropped.
How do I modify the following schema, so it also accepts float and int for the CONF_ADS_VALUE?
This will accept floats, ints, and strings that represent floats or ints, and will convert them all to a float. So, e.g., 1 will be converted to 1.0.
If, however, you want it to return an int if an int, or a string representing an int, is given, and a float only if a float, or a string representing a float, is given, then you could try:
the float value is passed correctly, but the service errors on the integer values.
It seems that pyADS doesn’t like float values when it’s expecting an integer.
That’s why the following also doesn’t work:
vol.Required(CONF_ADS_VALUE): vol.Coerce(float),
So I need to make the schema dependent on the value that is passed via
CONF_ADS_TYPE
so it uses
vol.Coerce(float)
when the value is REAL
and uses
vol.Coerce(int)
for all other values (int, udint, byte, bool, dint).
After browsing the ads & pyads code a bit, it seems you need to do a bit more. I didn’t try to understand everything, and I certainly can’t test anything, but it seems like maybe you need:
def handle_write_data_by_name(call: ServiceCall) -> None:
"""Write a value to the connected ADS device."""
ads_var = call.data[CONF_ADS_VAR]
ads_type = call.data[CONF_ADS_TYPE]
value = call.data[CONF_ADS_VALUE]
if ads_type != ADSTYPE_REAL: # NOT SURE IF THIS IF STMT IS NECESSARY
value = int(value)
try:
ads.write_by_name(ads_var, value, ADS_TYPEMAP[ads_type])
except pyads.ADSError as err:
_LOGGER.error(err)