Microservices In Embedded Systems

Microservices In Embedded Systems

I don’t write many “technical” posts, finding people and organisations more challenging, and hence more interesting, but this is one. If you like the diversion, let me know and I’d be happy to write some more such posts.

Some years back I was running a boutique embedded systems development company, in partnership with a hardware engineer. He’d design and build the hardware – micro-controller based – and I’d implement the core functionality in software. Mostly in C, C++ or Python, with some e.g. PIC assembler here and there. OSes were Linux, WindowsCE, or naked. Approach was entirely Agile (on both the hardware and software fronts).

We specialised in hyperconnected devices – now more widely known as the Internet of Things – so every device we designed centred around an embedded web (HTTP) server.

One particular project – at the higher end of micro-controller capabilities, with virtual memory addressing and a fairly beefy CPU – was an event logging device with e.g. remote access (dial-in or ethernet) capabilities, a touch panel for local admin, and a bunch of digital I/O lines for scanning the connected devices to be logged.

I chose Python as the prime option for the implementation, with Javascript and CSS for the touch UI, some C for low-level hardware (device driver) functions, and Json for initial device configuration a.k.a. policies.

Once I had a Python implementation that would run on the platform, I gave some thought, as I was writing some early code, to a suitable architecture. I knew the client had a vague interest in extending the range of product variants in the future, as well as possibly adding more features, so although not a priority, extensibility was at the back of my mind.

Aside: Another reason for Python being the favoured implementation language was the excellent CherryPy webserver package, which I had used often before. Unfortunately, it turned out that CherryPy wouldn’t run on the platform (WindowsCE), and tight schedules did not permit an investigation as to why. So I went with a basic SimpleHTTPServer implementation instead.

More pressing, in terms of getting the whole thing working, was the memory usage of each Python process. And the relative shortage of memory on the device (suggested by the economics of the design). This consideration was paramount, it turned out, and a good deal of the work was a consequence of shoe-horning the necessary functionality into the memory space of the device.

Eventually, the architecture evolved into circa a dozen separate, cooperating Python processes. (Note: I stuck with Python, because actually implementing the necessary functionality in Python was much quicker and less painful than doing the same in e.g. C or assembler).

In retrospect, today we might choose to call this a microservice architecture. Each Python process ran independently of the others, doing its small bit, and interacting with one or more of the other services as and when necessary.

The microservices included:

  • Watchdog
  • MCP
  • Networking
  • TimeWarden
  • MediaWarden
  • EventScanning
  • EventLogging
  • Webserver
  • RemoteCommandListener
  • SyncSource
  • DeviceStatus

Aside: Actually, there were rather more microservices than this originally, but I had to combine some in order to meet the memory constraints.

At the end of the project, it was clear (to me, not to anyone else) that, serendipitously, the architecture was such that adding new features, even whole new microservices, would be a piece of cake. I’m not aware that this was ever appreciated, let alone acted upon (no one else involved was at all software savvy).

Have you worked in embedded systems development? Have you ever seen or considered the pros (and cons) of a microservices-style architectural approach?

– Bob

Further Reading

Stop Thinking About User Interface ~ Juan José Ramírez
Windows CE: Synchronization Objects – Events ~ Bruce Eitman

5 comments
  1. Dendyard said:

    After a time, this is a brilliant post. 🙂 I have thought the same thing for a device driver.

  2. Sjoerd V. said:

    I’m looking for a similar approach to my Linux/Python embedded project. It runs on a fairly powerful, but single core CPU (early RasPi) and I have trouble getting the Python threads to work in parallel for the events that can be handled concurrently. Therefore (and all other reasons) these microservices really appeal to me. My biggest question at this point, how do you communicate between the processes and what’s the latency impact on this (I’m concerned about lagging button presses impacting user experience). Thanks.

    • Apols for missing your question. Please see most recent answer/comment.

  3. Austin said:

    Same question here about inter process communication – what was your general approach?

  4. In this case I used some combination of techniques for inter-process communication: TCP and UDP pipes, files, WinCE event flags, and for ultra-low latency comms, some custom code (shared memory guarded queues using WinCE synchronisation primitives) in the device driver I wrote for controlling the hardware.

Leave a comment