Expert advice sought -- writing an ESPHome Custom Component with a proprietary synchronous serial protocol

I have set myself the challenge of writing an ESPHome Custom Component to work with the Scantronic 9940 or 9941 keypad.

Screenshot 2024-05-31 at 21.31.17

The keypad was originally designed to work with the Scantronic range of alarm system control units, but if I link it into ESPHome and Home Assistant it could serve a number of purposes. The device has not only a numeric keypad, but also a 16x2 LCD display, an RFID tag reader, and some more LED lights, switches, and sensors.

I do not know if many others will be interested in such a specialised application (comments welcome below), but I would anyway like my code to be in line with ESPHome standards and conventions, and of course I would like to re-use any useful code that already exists! I am an experienced electronic engineer and C++ programmer, but this is the first time I would be contributing to an Arduino or ESPHome library. I am therefore looking for guidance from an experienced developer to help me navigate the plethora of documentation and source code available and point me in the right direction.

A few details known so far

I have no documentation so am reverse-engineering the protocol from the bottom up, starting with the data link layer as seen by a two-channel digital storage oscilloscope.

The device uses a proprietary synchronous data communication protocol over two wires – Data and Clock. It operates at 2KHz. The protocol is a little like I2C, but does not have exactly the same timings of data and clock, and has no ACK bit. It generally transmits 3 bytes at a time, whose functions I do not yet know – presumably something like the target keypad address, what data is being sent or is wanted, and the data itself.

It is not close enough to I2C to use the processors’s on-board hardware, which is what I assume the ‘Wire’ library does, so I will have to write the whole protocol in code, manipulating the GPIO high and low transitions directly.

Some kick-off questions

  1. Since the data comm protocol is similar to i2c, I presume it would make sense to clone the ‘i2c’, ‘i2c_bus’ and ‘wire’ libraries by way of example, then give them new names - like ‘st994x’, ‘st994x_bus’, and ‘st994x_io’.

  2. Since the protocol is going to be in software, there will be code inside (or underneath?) ‘st994x_io’ (the new ‘wire’) to do the actual read and write operations – is there a precedent for this?

  3. I want the entities presented by ESPHome to be compatible with the relevant Home Assistant add-ons and integrations such as Display, Alarm keypad, and Tag Reader – how can I be sure that is the case? For example, do I treat each numeric key as a binary_sensor, or do I capture one character or all characters in an input_text entity?

  4. Should I make a HA integration as well as the ESPHome component?

Thanks in advance of your guidance and ideas.

  1. Yes, that’s the usual approach is to copy a component that is similar to what you need and customize it to your needs as a custom component
  2. Sure, that’s normal.
  3. First I would suggest identifying what fields that you think HA needs for any of those integrations. ie. binary fields, text fields, numeric, etc and then add those to your yaml as template sensors. Your custom component can then publish it’s values to the template field from within it’s back end code by using it’s assigned ID in whatever form the field needs. ie. binary: bool, text: char or string, number: numeric
  4. Just worry about the ESPHome component . That’s the trickiest part. The HA side is easy enough as you will taylor your component to make it easy for HA to access.

FYI, here’s an example of what I mean. Please note that it is quite a bit more convoluted than what your needs are but it shows the use of custom components and template fields.

Great! Thanks for the prompt response. That is most encouraging. :+1:

So far I found it hard to establish that! I cannot easily find this information in the documentation. I could find out by experiment, probably, but then I would need example hardware such as a different keypad, LCD display and tag reader.

Your GitHub documentation pages are a good example of how to write such pages. I will need a little more time to go through the code, but it makes my project look feasible at any rate :slightly_smiling_face:

There is more than one way of doing it really. HA yaml can easily transform or use any output provided by your sensor to fit in any app that needs input. The key really to provide a field that can be seen by HA. Why don’t you just start with just having your custom component provide numeric output on keypress to one field. You can easily change the fields types, and output later.

1 Like

Thanks.

During development, do you recommend keeping the new source files locally on my system, then transfer to Github later, or put them on Github from the get-go (and mark them private until they are ready?)

Absolutely. I always work from local files first. No rush uploading to github until you have something working.

1 Like

This seems like a lot of effort to preserve a very ugly piece of gear. Especially when you could replace it with a nice 4 in touch display.

Could and may well do.

Primary keypad is the HA dashboard on residents’ mobile phones. A keypad / wall dashboard is handy for visitors, or in case the mobile network is down, or the residents lose their phones. Having a wired keypad is more secure in case Zigbee or WiFi is down or tampered with.

Mostly, the reverse-engineering is a fun challenge (!)