Starting point for serial write and read

Hi there,

Can anyone provide me some basic Serial config and write/read samples for developing a custom intgeration? I would like to communicate via Serial port with an Arduino based board. I really would like to know how I can simply write and read to serial port from my custom integration.

Since i used to run my HA on a virtual HyperV machine.
This limited my options, as a serial port wasn’t available. I also didn’t want to end up pulling long cables either.
So I used serial2tcp and i ended up sending/receiving tcp with a EspHome module flashed with JeeLab

my code:

I would look at an existing component that does serial, like Serial - Home Assistant

Or maybe that integration will do what you want?

Hi, thanks for your replies!

Let me clarify a bit what I would like to achieve. I made this RF USB dongle to wirelessly control mechanical home ventilations.

This will be connected to my Raspberry Pi and shows up as a virtual com port. To communicate with this USB dongle, I need to implement serial read and write commands. I would like to make my own custom HA integration for this. I already looked at: Link. But I think here it is not clear how to write to serial port?

At this moment, the USB dongle runs Firmata to communicate with HA, not optimal.

Yes I think that the serial integration is a sensor only, and therefore only reads serial. However it uses pyserial-asyncio so that probably gives a hint.

Firmata is the standard way of serial comms with an arduino type device. If you are having problems (you haven’t said in what way it is “not optimal”) why not post a github issue?

The idea of Firmata is to have control over Arduino’s IO’s in HA, that is not what I want to achieve, I would like to control and read out the actual the fan speed, this is done by sending RF messages with my onboard RF chip and report back to HA via Firmata. Currently I have to use the Firmata “light” entity for this, since I have to have an analog value. Instead I would like to use the FAN entity. Besides it seems that my implementation seems to lose connection after a few days for some reason, cannot find the reason for that. It might be much simpler to implement lightweight response/request communication protocol for sending/requesting FAN speed.

I thought it should be doable to create my own custom integration, since there are other integrations using serial read/write as well.

Frankly esphome would have been easier.

Problaby, but I would like to do it in python. In the meantime I figured out that I need serial_asyncio.

In the meantime, I know how to send and receive data on the Serial port. What I’m still not sure about, how to implement a simple FAN entity. How can I then see the entity attribute?

Thanks, my simplified code now looks like this:

import json
import logging

import asyncio
import serial_asyncio
import voluptuous as vol

from homeassistant.components.fan import (FanEntity, PLATFORM_SCHEMA, SUPPORT_SET_SPEED, ATTR_PERCENTAGE )
from homeassistant.const import (CONF_NAME, STATE_OFF, STATE_ON, STATE_UNKNOWN)
from homeassistant.core import callback

from homeassistant.const import CONF_NAME, CONF_VALUE_TEMPLATE, EVENT_HOMEASSISTANT_STOP
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity

_LOGGER = logging.getLogger(__name__)

CONF_SERIAL_PORT = "serial_port"
CONF_BAUDRATE = "baudrate"

DEFAULT_NAME = "USB Dongle"
DEFAULT_BAUDRATE = 115200

CONF_UNIQUE_ID = 'unique_id'
CONF_DEVICE_CODE = 'device_code'
CONF_CONTROLLER_DATA = "controller_data"
CONF_DELAY = "delay"
CONF_POWER_SENSOR = 'power_sensor'
ATTR_PERCENTAGE = "percentage"

#******************************************************************************************#
#                                                                                          #
#                            Params                                                        #
#                                                                                          #
#******************************************************************************************#
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
    {
        vol.Required(CONF_SERIAL_PORT): cv.string,
        vol.Optional(CONF_BAUDRATE, default=DEFAULT_BAUDRATE): cv.positive_int,
        vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
        vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
    }
)
#******************************************************************************************#
#                                                                                          #
#                            Setup                                                         #
#                                                                                          #
#******************************************************************************************#
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
    """Set up the Serial fan platform."""
    name = config.get(CONF_NAME)
    port = config.get(CONF_SERIAL_PORT)
    baudrate = config.get(CONF_BAUDRATE)

    value_template = config.get(CONF_VALUE_TEMPLATE)
    if value_template is not None:
        value_template.hass = hass

    fan = FanEntity(name, port, baudrate, value_template)
    
    async_add_entities([fan], True)

#******************************************************************************************#
#                                                                                          #
#                            FAN CLASS                                                     #
#                                                                                          #
#******************************************************************************************#
class FanEntity(Entity):
    """Representation of a Serial fan."""

    def __init__(self, name, port, baudrate, value_template):
        """Initialize the Serial fan."""
        self._name = name
        self._attr_unique_id = "123456"
        self._state = None
        self._attr_percentage = None
        self._port = port
        self._baudrate = baudrate
        self._serial_write_task = None
        self._serial_read_task = None
        self._template = value_template
        self._attributes = []
        self._last_on_speed = 2
        self._speed = 1
    
    async def async_added_to_hass(self):
        """Handle when an entity is about to be added to Home Assistant."""

    @property
    def unique_id(self):
        """Return a unique ID."""
        return self._attr_unique_id

    @property
    def name(self):
        """Return the name of the fan."""
        return self._name

    @property
    def should_poll(self):
        """No polling needed."""
        return False

    @property
    def state(self):
        """Return the state of the fan."""
        return self._state

    @property
    def percentage(self):
        """Return speed percentage of the fan."""
        return self._attr_percentage

    @property
    def extra_state_attributes(self):
        """Platform specific attributes."""
        return {
            'last_on_speed': self._last_on_speed,
        }

I can see the attribute “last_on_speed” in my automations, but I would like to see (and control) the percentage as well, what can be wrong here?

Your FanEntity class is not inheriting FanEntity but Entity, therefore your percentage property does not exist on Entity to override. Your class definition should be:

class FanEntity(FanEntity):
    """Representation of a Serial fan."""
....

Thanks for the hint, and sorry for late reply. Still it doensn’t work. I would really like to see a very basic implementation of the fan entity.

Look at this core integration for an example of a fan entity.