This article is a walk through all the different aspects to consider when it comes to programming for the Internet of Things, as opposite of the Web.
The used language is the most modern JS we all love, the used patterns though … far far away from what you would imagine. As example …
Forget about Promises
When you think about your journey through any elevator you think in sequences of well defined goals:
- press the floor button … then(…)
- close the doors … then(…)
- reach the floor … then(…)
- open the doors … finally() get out
Easy peasy lemon squeezy, right? But here is what happened instead:
- press the floor button … then(…)
- close the doors … uh wait, Zed’s coming in too …
- Zed’s dead chunked by closing doors baby, Zed’s dead
- reach the floor … uh wait, somebody just clicked a floor in between the one you entered and the one you’re getting out
- open the door … then(…)
- congrats, you’ve finally() reached the wrong floor 🎉
Do you see the issue? When you deal with hardware, the time in between operations is used to perform more operations and it could be rescheduled at any time. There’s no promise in a vehicle that should go from point A to point B, and the same applies to mostly every device we give for granted:
- the washing machines monitors water leaks and prematurely stop if any
- automatically closing doors keep monitoring in between to eventually reopen and re-schedule the planned closing action
- your iron would probably stop if it’s burning some clothes!
It’s all about Signals
The DOM has events that propagates automatically while NodeJS has events with a default limit of max 10 listeners per event.
The Internet of Things instead is connected through signals that are sent and/or received all the time. A proximity sensor sends signals with proximity data. A weather station sends signals with all sensors data. It’s all about being able to receive and understand these signals, and orchestrate the rest accordingly.
It’s Object Oriented Programming
I’m sorry for functional programming aficionados but there’s absolutely nothing more natural than OOP to program, literally, objects.
We can talk about immutability benefits as much as we like but reality is that hardware devices do have a state and it does change over time.
If you want to keep track of all changed states it’s a different story but you’re also overestimating the environment because …
Code size and RAM are precious
Microcontrollers have few KB or available memory to run our software:
- no place for over bloated abstractions
- no space for immutability, GC and memory do cost
- no much place for libraries and utilities too
Accordingly, the code which is targeting modern ESM compatible browsers I’ll show you in this article, will use the least amount of 3rd parts code to produce a small, yet readable, software capable of 100% simulating an elevator.
Don’t you believe me? Let’s start from the basement floor!
That’s pretty much it: every hardware we need will extend this class to be able to listen, or receive, signals and react accordingly.
A button in IoT is one of the most basic component able to cover thousand use cases. It does just one thing, and one thing only when you press it: it communicates it’s pressed and just about nothing else: AMAZING!
Wait … you are right … above is actually a labelled button because it has a symbol associated. Indeed, the most basic button could just have
press() method and call it a day. We can monkey patch the label on top later on with a sticker, if we want, or a colored pen or … whatever you like, really.
Proximity sensors are very common in the IoT world and DIY projects.
Once switched on or off, these can detect people passing through, as example, so that elevator’s doors can eventually be opened again, in case these were closing. To be able to simulate the sensor, I’ve exposed a
detect() method but basically a sensor would detect for us automatically (the demo is virtual though, I kinda can’t detect how close you are to the screen 🧐 )
What else do you think doors need to actually work?
Exactly !!! Automatic doors don’t happen by magic, these have a little engine that can either open or close them.
The main functionality of this engine is the ability to rotate either clockwise or anti-clockwise. That’s literally it. The rest is, for demo sake, signaled while rotating the engine.
That’s it, if we connect all the pieces of hardware and software we’ve used so far, we can demonstrate we have all we need to create semi-automatic doors.
The fully signal-driven logic involved to make these doors work is slightly more complex than previous hardware, so I’ve decided to not show them in here without comments and put a link for you instead, and also a demo.
As simple as it looks, this demo demonstrate that buttons signals can alterate the current status of the doors, the sensor in between can make doors reopen, and the motor signal can drive already a visual panel, like the progress bar on top, and also the current set of doors.
Is anything else missing?
Even if apparently it provides nothing more than what a button could do already, panels are fundamental pieces when it comes to elevators.
One of the reasons is that these can simplify the handling of all contained buttons, so that the eventual controller in charge of making decisions can listen to panels instead of every single button. You got it, panels are like a little utility / abstraction layer to simplify everything else life, but these are also simple.
Have you noticed that cute single button has a light too?
If you’ve paid attention during your elevator related journeys, you might have noticed that buttons with lights are not like buttons we use for lamps: if we press these, the light won’t necessarily switch on or off, it’s a completely separate functionality that is actually independent from the button itself.
Maybe the light comes up while you press it, but that doesn’t mean that the action will happen … or the other way around, the button light was already on and if you press it it won’t switch off until the elevator controller decides the time to do so.
It’s funny how little things could be programmed totally differently from what we would expect.
The Light Button
In this simple page I am actually using Web UI (button) to drive above class.
It’s fundamental to understand that the button by itself would not switch on its own light, unless programmed so, it’s all done indirectly.
I do have a live light button demo but I didn’t bother with a CodePen, sorry.
Doors motor can move both internal and external doors, once activated, but it wouldn’t be able to carry the whole elevator at its full capacity.
For this reason, a much bigger motor, most of the time also faster, is needed.
I know … I know, I’m just abstracting as much as I can all classes here …
I hear your thoughts going through “It’s that it already?” and the answer is no.
Beside the light buttons, useful only to have wonderful panels here or there, the only missing bit for the elevator was above bigger motor.
If you think about it, an elevator does not strictly need doors to operate and doesn’t need panels or light buttons to move. An elevator is actually quite a dumb piece of hardware that does one thing only: it reaches different floors and indeed
reach(level) is the only exposed method which technically could be summarized as
move to indicate the elevator should move.
level part is already an abstraction of the whole process, like pretty much the rest of the post is, but I hope you followed the logic so far.
This is the most complex piece of the puzzle: the elevator central controller.
The version I’ve written is everything but smart, and yet you’ll realize quite articulated. Following the list of responsibilities for such “black box”:
- all panels communicates to the controller
- all buttons are activated, considered, or ignored, by the controler
- doors are fully handled by the controller
- so is the elevator
The class constructor is indeed
constructor(elevators, doors, panels) and everything is organized through a mutable state that at any time knows what the best thing to do: ignore action, execute it ASAP, append action for later.
This controller is indeed the classic dumb elevator we all complained about at least once in our life: the one that just goes one pressed floor after the other instead of stopping in between! (press 0, then 10, and while you go up press 9 and reach 9 after you’ve reached 10).
The reason is that re-scheduling the tasks queue is an exercise full of interesting use cases (more later on) so I’ve focused on providing the most basic playground to let you experiment on top.
On the left, a panel with a single button per each floor while on the right there’s the internal elevator panel with all the options.
As you would realize, there’s a lot of logic to drive the whole code via Web UI, but that’s some overhead we won’t have programming IoT because we’ll have much worse problems to deal with 😂😂😂
You hopefully agree with me thought that’s oddly satisfying to put all these little hardware components together and have our own programmed elevator.
But how many things are we still not considering, believing it’s that easy?
We’d fool ourselves believing that software
doors.open() call is all it takes to open elevator doors. There are mechanical switches all over the structure to ensure that doors won’t open when the elevator is not at the floor.
External doors might also be directly driven by elevator internal doors so that these need to be hooked when the floor is reached.
Have you ever wondered why some building has just one button to call the elevator, while others have two of them, indicating if you want to go up or down?
If there’s no levels to reach direction it’s basically impossible to program a smarter elevator. If the controller tries to be smarter it will fail.
As example, my demo will simply queue all floors: first come first serve. That is actually better than the following scenario:
- Joanna goes from floor 10 to ground floor
- Luca is at floor 3 and needs to go to 9
- the smarter elevator re-schedule floor stop at 3 because it’s between the current floor and the next one to reach.
- Luca enters at 3
- the elevator reaches 0 .. and so does Luca
- Luca now goes up to 9
If there were people after Luca pressing buttons between 0 and 9, Luca would’ve waited everybody interfering with his levels for no reason whatsoever.
This kind of elevator is most likely developed in hell.
However, with directions the re-scheduling might actually make sense and in some case improve the perceived waiting time.
Self (Machine) Learning + Timing
This is an elevator I’ve never witnessed in my life. It’s an elevator that knows where to be and at which time is better to be there.
I give you an example. In your office, every single day of the week, pretty much every day of the week of the year, there is some rush hour where your elevator brings everybody in.
Here the thing: that elevator could immediately go back to the ground floor every time it reaches the last level in its queue and there’s nobody inside.
You know what I mean? Bring everyone to the floor … now, close the doors automatically like any elevator does, and if there’s no next level, and it’s between 8am and 10am, go back to the entrance right away so that everyone that’s arriving will find the elevator already there instead of waiting for it to come down empty … I mean … right?
But even if this sounds too simple to be not the default already, I’ve just added an extra layer to the stack: a database.
Nothing that SQLite wouldn’t be able to solve, of course, but are we willing to put extra costs, extra maintenance, extra complexity, to an object that useful that could compromise an entire company if malfunctioning?
Well … I hope at least my dumber elevator won’t break for the next few years.