Saturday, 30 April 2022

Automating heating vents with openHAB, esp8266 and LEGO - Part 2.5; Hardware rework

Working with hardware is fun; working with LEGO hardware is awesome. So before proceeding with the next part of my heating vent automation series, I took the opportunity to refine my vent manipulator, with the following aims:

  • Quieter operation; v1 sounded like a coffee-grinder
  • Faster movement; to sound like a quieter coffee-grinder for less time
  • Lower stack height above floor level; to avoid impeding the sofa-bed mechanism directly overhead

V1 Hardware

As a reminder, here's the first hardware revision featuring a LEGO Technic XL motor and an extremely over-engineered - and tall - chassis.

V2 Hardware

Here's the respun version, which works as well as, if not better than, the original.

The changes:

  • The chassis is half as high above the vent surface
  • The rack-and-pinion mechanism is centered in the chassis to reduce torque
  • The rack is situated lower to reduce flex
  • The motor is reduced in size to a LEGO Technic "M" motor (quieter and faster)
  • The manipulator clamps to the vent with a Technic pulley instead of a brick, further reducing height-above-floor

Now we're in a really good position to get down-and-dirty with some firmware...

Saturday, 26 March 2022

Things people have trouble with in React / Javascript, part 1: Too much React state

I've been on a bit of a Stack Overflow rampage recently, most commonly swooping in and answering questions/fixing problems people are having with their React apps. I'm going to spend my next few blog posts going over what seems to be giving people the most trouble in 2022.

Episode 1: In which things are overstated

This problem typically manifests itself as a question like "why doesn't my UI update" or the inverse "my UI is always updating" (which is almost always related to useEffect - see later in this series). With the useState hook, state management becomes so easy, it's tempting to just scatter state everywhere inside a component instead of thinking about whether it belongs there, or indeed if it's needed at all.

If I see more than 3 useState hooks in one component, I get nervous, and start looking for ways to:

  • Derive the state rather than store it
  • Push it up
  • Pull it down
The React docs (and Dan Abramov himself) talk a lot about pulling-up and pushing-down state, but I think deriving state may actually be more important than either of those.

What do I mean? Well, I see people doing this:

    const [cars, setCars] = useState([]);
    const [preferredColor, setPreferredColor] = useState(undefined);
    const [preferredMaker, setPreferredMaker= = useState(undefined);
    // DON'T DO THIS:
    const [filteredCars, setFilteredCars] = useState([]);
Obviously I've left out tons of code where the list of cars is fetched and the UI is wired up, but honestly, you can already see the trouble brewing. The cars list and the filteredCars list are both held as React state. But filteredCars shouldn't be - it's the result of applying the user's selections (preferred color and maker) and so can be trivially calculated at render time. As soon as you realise this, all kinds of UI problems with staleness, flicker, and lag just melt away:
    const [cars, setCars] = useState([]);
    const [preferredColor, setPreferredColor] = useState(undefined);
    const [preferredMaker, setPreferredMaker= = useState(undefined);
    // Derive the visible list based on what we have and what we know
    const filteredCars = filterCars(cars, preferredColor, preferredMaker);

I think some people have trouble with their mental model around functional components, and are afraid to have a "naked const" sitting there in their function - somehow it's a hack or a lesser variable than one that useState handed you. Quite the reverse I think.

Another argument might be that it's "inefficient" to derive the data on each and every render. To that, I counter that if you are maintaining the cars and filteredCars lists properly (and this is certainly not guaranteed), then the number of renders should be exactly the same, and thus the amount of work being done is the same. However there's a strong chance that deriving-on-the-fly will actually save you unnecessary renders. I might keep using this car-filtering analogy through this series to explain why this is.

Saturday, 26 February 2022

New Toy

I just received this from the good folk at PowerPal:

This is a cool device that basically should give me real-time API-based access to the power usage of my house. The next logical step for me is to then bundle it up into my openHAB setup. I'll probably begin with just using the HTTP binding to get what I need, and maybe (and it's a BIG maybe) turn it into a genuine binding at some point in the future. My experience trying to get the Broadlink binding merged into the openHAB addons codebase has turned me off that process a little...

Saturday, 29 January 2022

2022 To-Do List

There's just never enough time and/or motivation to do all the things I've got on the back-burner, but some of these have been around for just too long. Hopefully listing them here (and ideally ticking them off with suitable links) will be motivating...

  • The openHAB Broadlink Binding still hasn't been merged into the openHAB codebase. Every week it becomes harder - with such a busy upstream repository, with very exacting code-review standards, it's like nailing jelly to the wall ... of a moving train.
  • frenzy.js my browser-based retro 8-bit arcade game has been rotting for years now. It needs a full React upgrade and some deep thought (or reading-up, or both) about some of the basic game algorithms (like collision-detection, for example)
  • Tons of openHAB mini-projects to automate things around the house - blinds, heating vents, all sorts of stuff

Wish me luck...