Introduction
I have a handful of smart plugs from Maginon (SP-1E) at home. They are smart plugs that can be switched and measure the power consumption (and Energy consumption). There is no component available for Home Assistant, but when browsing in the integrations, I saw that an Edimax integration is there. Since the Maginon smart plugs are similar to one type of the Edimax SP-1101 ones, I thought integration would be easy... Now I know better. :-) I am not a programmer, but have an analytic mind and I understand some basic principles from programming languages and code. When you are an experienced programmer, all of the below might sound plain simple to you, but this article is intended to help others like myself in the world of custom components for HA with no to only limited knowledge of Python or programming.
What is my device like that I try to integrate?
It is smart plug outlet which actually allows me to control the switch (on/off) of an outlet and allows me to measure power, energy consumed, see actual voltage or current. So it is more than just a switch, it is a sensor (measurement device) as well. It runs Busybox Linux and can be accessed via telnet (command line access) or a web interface (http). It is connected to a 2.4Ghz Wifi network.
Where did I start from?
I used the Edimax integration as an example for my code (from oct/2020). I took me some time but I found out that there are 2 major parts in the integration and there is 1 configuration part.
Integration:
- smartplug.py (under x)
- switch.py (under y)
Configuration:
- configuration.yaml (under z)
Deeper dive into the Edimax integration & configuration for Home Assistant
This code will declare to HA that a switch entity is available but also that there is sensor information that can be read out. The code can be split up into the following parts:
- Import the smartplug library explained hereunder (see smartplug.py) and some other dependencies
- Define a new "domain": edimax
- Extend the platform schema (edimax) so that we can specify a host, username and password
- Set up the platform and add entities (as much as we define, and for this code: just 1)
- Define a new class to describe the smart plug entity (as added under step 4)
- Initialize the class (__init__) with some standard (required) parameters and some optional
- Define properties (values, states or readings) that are available or required for this entity
- Required (mandatory to define)
- unique_id (as the name states, something that makes this entity unique, not just the device or the component)
- Optional
- Your own properties that you want to expose or make available in HA
- Define some methods which are specific for the type of entity (switch) that we are adding, including what properties (values) to update (and how)
Since the architecture of HA has evolved since the creation of this entity, the original Edimax integration should be split up into a switch.py and sensor.py entity. The page on the device registry did shed some light and helped me understand how this should fit together. In short: a smart plug (device) like mine should have 2 or more entities (switch or sensor) which is seen as 1 component, when it has a config entry. Note that there will be a separate sensor entity for each measurement the smart plug is doing. (So a separate one for power, another one for voltage, current...)
So in my code, I started to split into switch.py and sensor.py but I'll explain that later.
Here, the actual library is available that does all the work to get data from the smart plug. It will do in short the following:
- Import dependencies
- Create a class SmartPlug (which is then used in the switch.py code)
- Initialize and create a new instance that will connect to the smart plug on port 10000
- Methods for sending or formatting XML to the device to set/get info, power or state
And of course, it is from within switch.py that these methods are being called.
configuration.yaml
This is where you need to "enable" your integration by adding it to the configuration of HA. As long as you don't define anything here, there will never show up something in HA.
Example code:
- platform: edimax host: 192.168.133.119 username: !secret switch_edimax_user password: !secret switch_edimax_password name: edimax1
How to install your custom library and define and enable devices in HA?
Step 1: install the custom library that does not exist in the PyPi repository
1.1 Create a new folder & copy the files there
a
1.2 Test with a local file
a
1.3 Adapt the manifest file
a
1.4 Create a setup.py file
You must create a setup.py file as per example below in x where pymaginon is a subfolder of.from setuptools import setup setup(name='pymaginon', version='0.2.1', description='Interface with Maginon Smart Plugs', url='https://github.com/smartathome/pymaginon', author='Smart At Home', author_email='smartathome2022@gmail.com', license='MIT', install_requires=['requests>=2.0'], packages=['pymaginon'], zip_safe=False)
Checklist before you install:
- You have created a directory for the library under /usr/local/lib/python3.9/site-packages/pymaginon
- Optionally: you have tested your code with your library in a test script
- You have adapted the manifest version
- You have created a setup.py file
1.5 Install via python3 setup.py install
bash-5.1# python3 setup.py install running install running bdist_egg running egg_info creating pymaginon.egg-info writing pymaginon.egg-info/PKG-INFO writing dependency_links to pymaginon.egg-info/dependency_links.txt writing requirements to pymaginon.egg-info/requires.txt writing top-level names to pymaginon.egg-info/top_level.txt writing manifest file 'pymaginon.egg-info/SOURCES.txt' reading manifest file 'pymaginon.egg-info/SOURCES.txt' adding license file 'LICENSE' adding license file 'LICENSE.txt' writing manifest file 'pymaginon.egg-info/SOURCES.txt' installing library code to build/bdist.linux-x86_64/egg running install_lib running build_py creating build creating build/lib creating build/lib/pymaginon copying pymaginon/__init__.py -> build/lib/pymaginon copying pymaginon/smartplug.py -> build/lib/pymaginon copying pymaginon/test.py -> build/lib/pymaginon creating build/bdist.linux-x86_64 creating build/bdist.linux-x86_64/egg creating build/bdist.linux-x86_64/egg/pymaginon copying build/lib/pymaginon/__init__.py -> build/bdist.linux-x86_64/egg/pymaginon copying build/lib/pymaginon/smartplug.py -> build/bdist.linux-x86_64/egg/pymaginon copying build/lib/pymaginon/test.py -> build/bdist.linux-x86_64/egg/pymaginon byte-compiling build/bdist.linux-x86_64/egg/pymaginon/__init__.py to __init__.cpython-39.pyc byte-compiling build/bdist.linux-x86_64/egg/pymaginon/smartplug.py to smartplug.cpython-39.pyc byte-compiling build/bdist.linux-x86_64/egg/pymaginon/test.py to test.cpython-39.pyc creating build/bdist.linux-x86_64/egg/EGG-INFO copying pymaginon.egg-info/PKG-INFO -> build/bdist.linux-x86_64/egg/EGG-INFO copying pymaginon.egg-info/SOURCES.txt -> build/bdist.linux-x86_64/egg/EGG-INFO copying pymaginon.egg-info/dependency_links.txt -> build/bdist.linux-x86_64/egg/EGG-INFO copying pymaginon.egg-info/not-zip-safe -> build/bdist.linux-x86_64/egg/EGG-INFO copying pymaginon.egg-info/requires.txt -> build/bdist.linux-x86_64/egg/EGG-INFO copying pymaginon.egg-info/top_level.txt -> build/bdist.linux-x86_64/egg/EGG-INFO creating dist creating 'dist/pymaginon-0.2.1-py3.9.egg' and adding 'build/bdist.linux-x86_64/egg' to it removing 'build/bdist.linux-x86_64/egg' (and everything under it) Processing pymaginon-0.2.1-py3.9.egg creating /usr/local/lib/python3.9/site-packages/pymaginon-0.2.1-py3.9.egg Extracting pymaginon-0.2.1-py3.9.egg to /usr/local/lib/python3.9/site-packages Adding pymaginon 0.2.1 to easy-install.pth file Installed /usr/local/lib/python3.9/site-packages/pymaginon-0.2.1-py3.9.egg Processing dependencies for pymaginon==0.2.1 Searching for requests==2.25.1 Best match: requests 2.25.1 Adding requests 2.25.1 to easy-install.pth file Using /usr/local/lib/python3.9/site-packages Searching for urllib3==1.26.6 Best match: urllib3 1.26.6 urllib3 1.26.6 is already the active version in easy-install.pth Using /usr/local/lib/python3.9/site-packages Searching for chardet==4.0.0 Best match: chardet 4.0.0 chardet 4.0.0 is already the active version in easy-install.pth Installing chardetect script to /usr/local/bin Using /usr/local/lib/python3.9/site-packages Searching for idna==2.10 Best match: idna 2.10 idna 2.10 is already the active version in easy-install.pth Using /usr/local/lib/python3.9/site-packages Searching for certifi==2021.5.30 Best match: certifi 2021.5.30 certifi 2021.5.30 is already the active version in easy-install.pth Using /usr/local/lib/python3.9/site-packages Finished processing dependencies for pymaginon==0.2.1
Step 2: add the component code under HA
2.1 x
sxx
Step 3: enable the component in the configuration of HA
xxx
And now restart HA or restart your container... and fingers crossed. :-)
General learnings and conclusion for myself
- Altough I respect everyone involved in the community of HA and I'm grateful for all the available support and documentation, I still find some of the documentation very limited, not always clear and some real life examples (beyond a simple "hello world") are often missing.
- There are some basic principles one needs to know (and respect) in order to be able to write a good component. Once you know these, it is more easy to build your own component.
- The source code (and architecture) of Home Assistant is still in progress. Components written years ago, might make use of api or functionality that has changed or is no longer allowed to be used. So using them as an example or base for editing could bring some surprises.
- Browse through the code tree and have a look at other components that are maintained and updated regularely. They are an excellent base for guidance and a source of inspiration (at least for me).
- If you want to make use of your own written library as a base (in my case, I adapted pyedimax to pymaginon), you will have to install it manually since it does not exist in the PyPI repository. Until of course you decide to add such library there.
- Use the logs that HA will throw out each time things don't work. They often will help you getting one step further. Also, make use of the LOGGER functionality so that custom error logs can be added when needed. When your code is more stable, look at how other components are making use of them, not to overwhelm your log files.
- I am currently making use of and "old way" of adding my entities to HA. add_entities has been superseded by the async way of doing things. Something for the future. :-)
Feel free to comment or share useful other links to help others in understanding how custom components can be created more easily.
No comments:
Post a Comment