Here is how platforms die: first, they are good to their users; then they abuse their users to make things better for their business customers; finally, they abuse those business customers to claw back all the value for themselves. Then, they die.
I call this enshittification, and it is a seemingly inevitable consequence arising from the combination of the ease of changing how a platform allocates value, combined with the nature of a “two sided market,” where a platform sits between buyers and sellers, holding each hostage to the other, raking off an ever-larger share of the value that passes between them.
Cory Doctorow
The examples he mentions hit home. While the changes from user-friendly to user-unfriendly are very gradual, seeing the bigger picture makes it pretty obvious that enshittification does happen.
I knew about Zigbee for a long time but never had a reason to use them: WiFi usually works better as long as battery is not an issue, and if it does, Bluetooth LE is really good.
And then I saw that Sonoff built a thing:
Ethernet-Zigbee gateway
Planned to support Matter
Allows IoT to run locally (no Internet needed)
No Internet means: much less latency, more secure and more stable
Powering on the iHost was simple: plug in. Works. Has a web interface. As easy as it sounds. There was no “firmware update” button and it did not update automatically. Turns out that this is only possible via its phone app. And to make that work, you have to let the iHost know your eWeLink account.
This software is in development so upgrading is pretty much mandatory.
Enabling the first wireless button
Since it’s battery-driven and the battery is already installed, there’s usually a plastic insulator to remove. How hard can that be? The instructions look simple:
That looks easy!
Turns out to be harder than expected: problem no. 1 was: how much force am I allowed to use to open that case? Too much force will break parts of plastic off, or break the whole thing, or make it visibly damaged. Also what exactly am I removing here? Just the bottom plate? There seem to be quite some plastic parts inside.
In short: it was confusing. So here some photos of the parts for future generations so they know what to do.
This is the bottom part which is the only part to pry off, and it’s easy to do once you know:
Bottom part. This is supposed to be removed to reach the battery insulator.
Those 4 noses are what holds it to the middle part. Use a flat screwdriver to pull those noses out one by one.
Here is the inner part with the battery and electronics:
The middle part. The actual button is the small thing in the middle. Below that is the board and below that is the battery.
The bottom side of the middle part with the holes for the noses of the bottom plate:
Bottom side of the middle part. You see the plastic insulator to pull out.
I had huge issues pulling out the insulator: it simply would not come out. The tab even broke off and I had to remove the battery, which was not easy at all:
Broken insulator. Once the battery is removed, the board is not held in any way to the plastic.
Re-assembly is very simple however. The arrows help a lot.
Here the top shell, but the inside, so you can see how and where it has flanges:
Top/outer shell, as seen from the inside. Note the nice arrows which make it easy to reassemble.
After inserting the battery again and re-assembling the top and the middle part, pushing the reset button for 5s makes it go into pairing mode. Works within 10-20s and was very reliable after upgrading the firmware to v1.5.5 (from v1.4.x which paired, but it did not tell me about it, so I paired again and again for no good reason).
Paired! What now?
Once some Zigbee devices are paired, you can connect their actions in an easy interface. Here an example which toggles Outlet 2 when I push the Button 2. A simple switch:
An example of a very simple workflow: push a button, and toggle power.
Other actions are: making sound (alarm clock or intruder alarms), or disarm all monitoring etc.
Summary
The iHost is a very neat concept: well thought out features at a good price. Plenty usability features, but also high geek and fun factor (API, runs containers).
It’s not perfect (No BLE, no WiFi, no camera integration, the TPU is not yet used as far as I can see).
The Zigbee devices are cheerful and cheap and their plastic shells are pleasant.
The distance Zigbee operates in this household is about as good (or bad) as Bluetooth LE: 1 wall only. 2 walls don’t work. Not sure what concrete they use here, but it blocks 2.4GHz quite efficiently. Thus I need more Zigbee devices which act as router.
PS: As I am writing this, v1.6.0 is out, and this time the web interface of the iHost allows me to upgrade.
I like Espruino on ESP32: It has WiFi, enough I/O to be useful and it runs on JavaScript (Espruino). The RP2040 from the Raspberry Pi Organization has one thing I have not seen though: a clever I/O engine which can be used to create various protocols with its surprisingly capable state machine.
This needs to be tested!
Cytron Maker Pi RP2040
So I went to my favorite electronics shop and got myself a Cytron Maker Pi RP2040. Initially a “normal” Raspberry Pi Pico would have been ok, but the Cytron has Grove connectors, a bunch of LEDs, servo connectors, a motor driver and a noise-making piezo. I got a lot of Grove modules from my M5Stack, so Cytron it was!
Once at home, turn it on, see and hear the demo, then flash with Kaluma. Nice CLI, but less interactive compared to Espruino. Tested the built-in WS2812B LEDs and they worked.
Kind’a. Colors worked as expected, and zero and max brightness worked, but anything between seemed random. I think I fixed it. Was a good introduction to the PIO state machine and its capabilities.
Then I tried to make the simplest I2C device I have available work with Kaluma: a VL53L0X TOF sensor and lo-and-behold: it worked! Package available here.
So far good fun for the ¥1240 I paid for the Cytron board!
No, I am a human and I wrote this very article. This one is all it is about. It was written either by an AI, or by a very bad article writer. I cannot say. The border between those two is very fuzzy.
Let’s start with some actual facts:
ZimaBoard is a small single board computer with an Intel N3350 (2 cores, 1.1-2.4GHz) or N3450 (4 cores, 1.1-2.2GHz) CPU. See here for more details. Names are ZimaBoard 216, 432, 832. The first digit is the amount of RAM in GB, the next 2 digits is the amount of Flash memory in GB.
Udoo Bolt v8 (see here for detailed specs) runs on an AMD Ryzen V1605B with Radeon VEGA 8 graphics. The older version Udoo Bolt v3 runs with a Ryzen V1202B and VEGA 3.
The Offending Blog Article
When reading this blog entry, the very first picture is already a bad start, but I gave it a benefit of doubt since everyone knows the size of a ZimaBoard and RPi4, so it’s like the banana for scale, but with a RPi4.
Showing a picture of a Raspberry Pi 4 and an Udoo Bolt
Stated specs for the Udoo Bolt v3:
Udoo Bolt v3 does not use a V1605B
Speaking of the various Udoo Bolt versions, it gets worse:
Udoo Bolt version inflation!
There is no V3 Plus, and how a human (or an AI) can write “The V3 and V3 Plus models are designed with an AMD Ryzen 1605B processor, while the V8 model is designed with an AMD Ryzen V1605B processor” is beyond me.
It Gets Worse
Keep in mind, this is a blog entry on the zimaboard.com web page, so making errors for a different vendor’s product (Udoo) is one thing, but you surely know your own products better. Or do you?
Almost nothing in this paragraph is correct
This is totally incorrect data, displayed with a confidence only ChatGPT can have. Nothing is correct in this paragraph: There are no A55E or A55E2 models, no ZimaBoard had ever a Celeron J3355 nor a Pentium N4200, 32GB (not 64GB) eMMC is all you get at most, and WiFi and Bluetooth you do not get. The only correct info is “up to 8GB RAM”, but it’s LPDDR4, not DDR3L.
Here is the part where I questioned whether someone put some alcohol into my morning coffee:
ZimaBoard CPU switcharoo
In one paragraph there’s two models: ZimaBoard A55E and A55E2, and then there’s two models ZimaBoard Basic and Pro. And they switched CPUs to be ARM based.
And it switches again in a later section:
ZimaBoard now has a AMD CPU
Here the ZimaBoard runs on an Ryzen V1807B. And again, while it states there’s WiFi and Bluetooth, the ZimaBoard has neither. Also no USB-C.
Let’s Try ChatGPT
Since this looks like a ChatGPT article, let’s try that:
Captured from ChatGPT
Yeah, that’s pretty much the same nonsense I read in the zimaboard.com blog page.
In Conclusion
I see a lot of low-quality (insert 4-letter-words here) articles on the Internet. To find it on the blog of zimaboard.com is very disappointing though.
I think what happened here is that ChatGPT was asked three times to write an article comparing the ZimaBoard and the Udoo Bolt. Each part in the blog entry was a separate ChatGPT request of the type “Write an article comparing the ZimaBoard and the Udoo Bolt focusing on X”. It would explain the repetitive nature, the jump in specs and the overall lack of “quality” in the whole blog article.
I was interested to get one of those ZimaBoards since it has 2 SATA ports which is pretty unique among low power SBCs. But when a company sets that low standards on their blog, chances are they cut corners somewhere else too.
At home I run my own small Certificate Authority (CA) via the fabulous Smallstep step ca. Importing the root certificate is not always straightforward, but in most cases it’s sufficient to let the OS know about a trustworthy CA. Firefox on Android however does not use that OS maintained root CA repository. To enable it you need to do several things:
Open Firefox on Android
Go to Settings
Scroll down, click on About Firefox
Tough the logo 7 times to enable Developer Mode
Go back
Now you have more entries, namely the “Secret Settings”
And there’s the “Use 3rd party CA certificates” which is the Android maintained one
Turn it on
Easy, but not intuitive at all. Now I can access the web interface of my Minio Server via https as it should be.
My father had a rowing machine when I was a kid: one of those piston ones. It was fun for 5 minutes, but it didn’t work well and it did not feel like rowing at all.
But rowing generally is a nice sport: not only is it fun to do on a lake, but it’s good training: uses plenty muscles like legs, core and arms and there’s no fast movements or excessive stress on joints.
So I was looking at rowing machines to test in the local gyms, but I could not find one, so I collected info from the Internet and settled on a Concept2 RowErg. The build quality, the lack of electricity needed to run it, the not-excessive noise level it creates, the size in use and when stored all played a role, but one of the best parts of it is the Performance Monitor PM5: it measures your power output in a very non-flashy way, but it’s very good at it. No silly gimmicks, no fancy touch screen and Internet connection.
The drawback is the size of the machine: 244cm long. Where ever you put it, it’s in the way. The noise on the other hand is not as bad as I thought, but it makes noise when worked hard since it’s effectively a very inefficient fan. A closed door makes it very tolerable though. I don’t dare to do 6 o’clock early morning or late night rowing though.
Long story short: while not cheap, I feel it’s well spent and I have one less excuse to not do some proper exercise.
I heard a lot about “if you want to control LEDs, use WLED“. I never had a need to control LEDs (the strip type), but today I had some spare time and I tested it with a spare ESP8266 and a single WS2812B LED. WLED is not really made for single LEDs, but as a proof-of-concept it’ll have to do.
Can’t say much here though: the install went as expected, connecting to the access point it created was straightforward, setting up my WiFi credentials worked, and controlling the single LED via web interface or Android app was as easy as it can get. This was one of the easiest installs of any IoT thing I ever had.
Now I do have to get me some LED strips to play a bit more with it…
Update: Ok, got myself a 60 LED WS2812B strip. And WLED effects look much better for obvious reasons. And you can split the 60 LEDs into segments and set their respective colors via curl easily:
Above sets the color of the 3rd segment to blue (assuming the effect is “Solid”). That’s way better and easier than any other API I’ve seen for WiFi connected lights.
Today via reddit I found a neat little utility I never heard of: uhubctl. It can turn off/on/toggle power on USB ports. And it works perfectly on my old 7 port USB 3 hub (look for the 1050:0120 Yubikey on hub 2-4.1 port 1):
❯ uhubctl
Current status for hub 3-4.1 [2109:0812 VIA Labs, Inc. USB3.0 Hub, USB 3.00, 4 ports, ppps]
Port 1: 02a0 power 5gbps Rx.Detect
Port 2: 02a0 power 5gbps Rx.Detect
Port 3: 02a0 power 5gbps Rx.Detect
Port 4: 02a0 power 5gbps Rx.Detect
Current status for hub 3-4 [2109:0812 VIA Labs, Inc. USB3.0 Hub, USB 3.00, 4 ports, ppps]
Port 1: 0263 power 5gbps U3 enable connect [2109:0812 VIA Labs, Inc. USB3.0 Hub, USB 3.00, 4 ports, ppps]
Port 2: 02a0 power 5gbps Rx.Detect
Port 3: 02a0 power 5gbps Rx.Detect
Port 4: 02a0 power 5gbps Rx.Detect
Current status for hub 2-4.1 [2109:2812 VIA Labs, Inc. USB2.0 Hub, USB 2.10, 4 ports, ppps]
Port 1: 0103 power enable connect [1050:0120 Yubico Security Key by Yubico]
Port 2: 0100 power
Port 3: 0100 power
Port 4: 0100 power
Current status for hub 2-4 [2109:2812 VIA Labs, Inc. USB2.0 Hub, USB 2.10, 4 ports, ppps]
Port 1: 0503 power highspeed enable connect [2109:2812 VIA Labs, Inc. USB2.0 Hub, USB 2.10, 4 ports, ppps]
Port 2: 0100 power
Port 3: 0100 power
Port 4: 0103 power enable connect [1852:7022 FiiO DigiHug USB Audio]
❯ uhubctl -a off -l 2-4.1 -p 1
Current status for hub 3-4.1 [2109:0812 VIA Labs, Inc. USB3.0 Hub, USB 3.00, 4 ports, ppps]
Port 1: 02a0 power 5gbps Rx.Detect
Sent power off request
New status for hub 3-4.1 [2109:0812 VIA Labs, Inc. USB3.0 Hub, USB 3.00, 4 ports, ppps]
Port 1: 0080 off
Current status for hub 2-4.1 [2109:2812 VIA Labs, Inc. USB2.0 Hub, USB 2.10, 4 ports, ppps]
Port 1: 0103 power enable connect [1050:0120 Yubico Security Key by Yubico]
Sent power off request
New status for hub 2-4.1 [2109:2812 VIA Labs, Inc. USB2.0 Hub, USB 2.10, 4 ports, ppps]
Port 1: 0000 off
❯ uhubctl
Current status for hub 3-4.1 [2109:0812 VIA Labs, Inc. USB3.0 Hub, USB 3.00, 4 ports, ppps]
Port 1: 0080 off
Port 2: 02a0 power 5gbps Rx.Detect
Port 3: 02a0 power 5gbps Rx.Detect
Port 4: 02a0 power 5gbps Rx.Detect
Current status for hub 3-4 [2109:0812 VIA Labs, Inc. USB3.0 Hub, USB 3.00, 4 ports, ppps]
Port 1: 0263 power 5gbps U3 enable connect [2109:0812 VIA Labs, Inc. USB3.0 Hub, USB 3.00, 4 ports, ppps]
Port 2: 02a0 power 5gbps Rx.Detect
Port 3: 02a0 power 5gbps Rx.Detect
Port 4: 02a0 power 5gbps Rx.Detect
Current status for hub 2-4.1 [2109:2812 VIA Labs, Inc. USB2.0 Hub, USB 2.10, 4 ports, ppps]
Port 1: 0000 off
Port 2: 0100 power
Port 3: 0100 power
Port 4: 0100 power
Current status for hub 2-4 [2109:2812 VIA Labs, Inc. USB2.0 Hub, USB 2.10, 4 ports, ppps]
Port 1: 0503 power highspeed enable connect [2109:2812 VIA Labs, Inc. USB2.0 Hub, USB 2.10, 4 ports, ppps]
Port 2: 0100 power
Port 3: 0100 power
Port 4: 0103 power enable connect [1852:7022 FiiO DigiHug USB Audio]
❯ uhubctl -a on -l 2-4.1 -p 1
Current status for hub 3-4.1 [2109:0812 VIA Labs, Inc. USB3.0 Hub, USB 3.00, 4 ports, ppps]
Port 1: 0080 off
Sent power on request
New status for hub 3-4.1 [2109:0812 VIA Labs, Inc. USB3.0 Hub, USB 3.00, 4 ports, ppps]
Port 1: 02a0 power 5gbps Rx.Detect
Current status for hub 2-4.1 [2109:2812 VIA Labs, Inc. USB2.0 Hub, USB 2.10, 4 ports, ppps]
Port 1: 0000 off
Sent power on request
New status for hub 2-4.1 [2109:2812 VIA Labs, Inc. USB2.0 Hub, USB 2.10, 4 ports, ppps]
Port 1: 0101 power connect [1050:0120]
❯ uhubctl
Current status for hub 3-4.1 [2109:0812 VIA Labs, Inc. USB3.0 Hub, USB 3.00, 4 ports, ppps]
Port 1: 02a0 power 5gbps Rx.Detect
Port 2: 02a0 power 5gbps Rx.Detect
Port 3: 02a0 power 5gbps Rx.Detect
Port 4: 02a0 power 5gbps Rx.Detect
Current status for hub 3-4 [2109:0812 VIA Labs, Inc. USB3.0 Hub, USB 3.00, 4 ports, ppps]
Port 1: 0263 power 5gbps U3 enable connect [2109:0812 VIA Labs, Inc. USB3.0 Hub, USB 3.00, 4 ports, ppps]
Port 2: 02a0 power 5gbps Rx.Detect
Port 3: 02a0 power 5gbps Rx.Detect
Port 4: 02a0 power 5gbps Rx.Detect
Current status for hub 2-4.1 [2109:2812 VIA Labs, Inc. USB2.0 Hub, USB 2.10, 4 ports, ppps]
Port 1: 0103 power enable connect [1050:0120 Yubico Security Key by Yubico]
Port 2: 0100 power
Port 3: 0100 power
Port 4: 0100 power
Current status for hub 2-4 [2109:2812 VIA Labs, Inc. USB2.0 Hub, USB 2.10, 4 ports, ppps]
Port 1: 0503 power highspeed enable connect [2109:2812 VIA Labs, Inc. USB2.0 Hub, USB 2.10, 4 ports, ppps]
Port 2: 0100 power
Port 3: 0100 power
Port 4: 0103 power enable connect [1852:7022 FiiO DigiHug USB Audio]
Neat as now I can power control all kind of USB devices and there’s plenty of stuff which uses USB as power source.
Deno can use shared libraries which follow the normal C convention, thus allowing Deno programs to call C functions. Since there’s no way to create raw Ethernet packets within Deno and I found no library doing this, I think I’ll have to create it myself similar to what I did with Dart and its FFI.
But first I wanted to know what the overhead of calling a C function in a shared library is as this GitHub issue seems to make it very slow.
Time to measure! So I created a simple C function to add up bytes in an array:
int sum(const uint8_t *p, int count) {
int res=0;
for (int i=0; i<count; ++i) {
res += p[i];
}
return res;
}
and call this with variable amounts of count, from 1 to 4096. From Deno call it:
for (let size = 1 ; size < buf.length; size *= 2) {
start = performance.now();
for (let i = 0; i < 1_000_000; ++i) {
result = dylib.symbols.sum(buf, size);
}
end = performance.now();
console.log(`Time used for ${size} bytes: ${end-start}ns`);
}
performance.now() returns a time stamp in ms, thus since the test call is done 1M times, the result shows the time in ns:
Bytes
AMD GX-420CA
AMD Ryzen 5 3400GE
RK3328@1.3GHz
Khadas VIM3L S905D3@1.9GHz
AWS C6G
4
38
12
1274
864
228
8
56
18
1342
902
232
16
90
34
1464
982
252
32
174
64
1698
1134
292
64
310
140
2170
1436
386
128
584
268
3120
2042
556
256
1130
544
4998
3252
904
512
2224
1022
8764
5678
1620
1024
4410
2048
16304
10520
3014
2048
8800
4072
31378
20200
5808
4096
17554
8076
61690
39598
11374
Overhead
23
14
1213
830
212
Calling FFI from Deno with increasing amount of work done inside the FFI, Deno version 1.29.3 (ARM: 1.29.4)
Linear regression shows 23ns and 14ns overhead (extrapolate for size=0) for the x86_64 CPUs. Note how nicely the time increases with larger payloads. The ARM CPUs start to show linear increases only at about 128 bytes, and their overhead is quite a lot higher at 830ns and 212ns.
Given that one 1500 byte Ethernet frame at 1 GBit/s takes 12μs, the overhead for the slower AMD CPU is only 0.2%, this is very acceptable. Even for more typical frames of 500 byte (128 pixel, 3 colors, plus a bit of overhead), the overhead is only 0.6%.
The ARM CPUs have significantly more overhead (7% for a 1500 byte frame for the S905D3, and 20% for a 500 byte frame). Even using a server type ARM CPU does not improve it by much.
Appendix
Deno version: 1.29.3 for x86_64, and 1.29.4 for ARMv8 compiled via