Add dehumidifier post

This commit is contained in:
2025-09-28 16:57:07 +01:00
parent ad573a79a0
commit 091a9c7dfc
12 changed files with 169 additions and 14 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

View File

@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Circuit Diagram, cdlibrary.dll 4.0.0.0 -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" width="500" height="280" xmlns="http://www.w3.org/2000/svg" style="background-color:white">
<rect width="100%" height="100%" fill="white"/>
<text x="400" y="180" style="font-family:Arial;font-size:11px;text-anchor:start" dominant-baseline="middle" transform="rotate(0, 400, 180)">power</text>
<text x="350" y="180" style="font-family:Arial;font-size:11px;text-anchor:start" dominant-baseline="middle" transform="rotate(0, 350, 180)">full</text>
<text x="200" y="80" style="font-family:Arial;font-size:11px;text-anchor:start" dominant-baseline="middle" transform="rotate(0, 200, 80)">5v regulator</text>
<line x1="470" y1="60" x2="470" y2="100" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="440" y1="60" x2="470" y2="60" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="400" y1="60" x2="407" y2="60" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="433" y1="60" x2="440" y2="60" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<ellipse cx="420" cy="60" rx="12" ry="12" style="fill-opacity:0;fill:rgb(0, 0, 0);stroke:rgb(0, 0, 0);stroke-width:2" />
<text x="420" y="60" style="font-family:Arial;font-size:12px;text-anchor:middle" dominant-baseline="middle" transform="rotate(0, 420, 60)">M</text>
<line x1="200" y1="60" x2="400" y2="60" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="470" y1="200" x2="470" y2="240" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="470" y1="100" x2="470" y2="132" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="470" y1="159" x2="470" y2="200" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="445" y1="132" x2="445" y2="160" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="430" y1="160" x2="445" y2="160" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="452" y1="130" x2="452" y2="135" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:4" />
<line x1="452" y1="143" x2="452" y2="148" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:4" />
<line x1="452" y1="156" x2="452" y2="161" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:4" />
<line x1="452" y1="132" x2="470" y2="132" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="452" y1="159" x2="470" y2="159" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="470" y1="168" x2="480" y2="168" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<ellipse cx="470" cy="168" rx="2" ry="2" style="fill-opacity:1;fill:rgb(0, 0, 0);stroke:rgb(0, 0, 0);stroke-width:2" />
<line x1="480" y1="146" x2="480" y2="168" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="452" y1="146" x2="480" y2="146" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<path d="M 455,146 L 459,149 L 459,143 L 455,146 L 457,148" style="fill-opacity:1;fill:rgb(0, 0, 0);stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="390" y1="210" x2="390" y2="240" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="340" y1="210" x2="340" y2="240" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="390" y1="160" x2="390" y2="180" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="310" y1="160" x2="430" y2="160" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="310" y1="180" x2="340" y2="180" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="340" y1="180" x2="340" y2="210" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<path d="M 340,202 M 332,202 L 348,202 M 340,202 L 348,187 L 332,187 L 340,202" style="fill-opacity:0;fill:rgb(0, 0, 0);stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<path d="M 340,200 M 351,198 L 359,206 M 360,207 L 358,203 L 356,205 L 360,207 L 358,203" style="fill-opacity:0;fill:rgb(0, 0, 0);stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<path d="M 340,200 M 344,204 L 352,212 M 353,213 L 351,209 L 349,211 L 353,213 L 351,209" style="fill-opacity:0;fill:rgb(0, 0, 0);stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="390" y1="180" x2="390" y2="210" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<path d="M 390,202 M 382,202 L 398,202 M 390,202 L 398,187 L 382,187 L 390,202" style="fill-opacity:0;fill:rgb(0, 0, 0);stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<path d="M 390,200 M 401,198 L 409,206 M 410,207 L 408,203 L 406,205 L 410,207 L 408,203" style="fill-opacity:0;fill:rgb(0, 0, 0);stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<path d="M 390,200 M 394,204 L 402,212 M 403,213 L 401,209 L 399,211 L 403,213 L 401,209" style="fill-opacity:0;fill:rgb(0, 0, 0);stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="310" y1="200" x2="310" y2="240" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<rect x="200" y="130" width="100" height="80" style="fill-opacity:0;fill:rgb(0, 0, 0);stroke:rgb(0, 0, 0);stroke-width:2" />
<line x1="190" y1="140" x2="200" y2="140" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="190" y1="160" x2="200" y2="160" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="300" y1="140" x2="310" y2="140" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="300" y1="160" x2="310" y2="160" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<text x="204" y="140" style="font-family:Arial;font-size:12px;text-anchor:start" dominant-baseline="middle" transform="rotate(0, 204, 140)"></text>
<text x="204" y="160" style="font-family:Arial;font-size:12px;text-anchor:start" dominant-baseline="middle" transform="rotate(0, 204, 160)"></text>
<text x="296" y="140" style="font-family:Arial;font-size:12px;text-anchor:end" dominant-baseline="middle" transform="rotate(0, 296, 140)"></text>
<text x="296" y="160" style="font-family:Arial;font-size:12px;text-anchor:end" dominant-baseline="middle" transform="rotate(0, 296, 160)"></text>
<line x1="190" y1="180" x2="200" y2="180" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="300" y1="180" x2="310" y2="180" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<text x="204" y="180" style="font-family:Arial;font-size:12px;text-anchor:start" dominant-baseline="middle" transform="rotate(0, 204, 180)"></text>
<text x="296" y="180" style="font-family:Arial;font-size:12px;text-anchor:end" dominant-baseline="middle" transform="rotate(0, 296, 180)"></text>
<line x1="190" y1="200" x2="200" y2="200" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="300" y1="200" x2="310" y2="200" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<text x="204" y="200" style="font-family:Arial;font-size:12px;text-anchor:start" dominant-baseline="middle" transform="rotate(0, 204, 200)"></text>
<text x="296" y="200" style="font-family:Arial;font-size:12px;text-anchor:end" dominant-baseline="middle" transform="rotate(0, 296, 200)"></text>
<line x1="160" y1="140" x2="190" y2="140" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="170" y1="90" x2="170" y2="140" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="140" y1="60" x2="145" y2="60" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="195" y1="60" x2="200" y2="60" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<rect x="145" y="35" width="50" height="50" style="fill-opacity:0;fill:rgb(0, 0, 0);stroke:rgb(0, 0, 0);stroke-width:2" />
<line x1="146" y1="84" x2="194" y2="36" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="168" y1="46" x2="151" y2="46" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="168" y1="50" x2="165" y2="50" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="161" y1="50" x2="158" y2="50" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="154" y1="50" x2="151" y2="50" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="172" y1="70" x2="189" y2="70" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="172" y1="74" x2="175" y2="74" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="179" y1="74" x2="182" y2="74" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<line x1="186" y1="74" x2="189" y2="74" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<text x="55" y="60" style="font-family:Arial;font-size:12px;text-anchor:end" dominant-baseline="middle" transform="rotate(0, 55, 60)">+9V</text>
<line x1="60" y1="60" x2="140" y2="60" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<text x="55" y="240" style="font-family:Arial;font-size:12px;text-anchor:end" dominant-baseline="middle" transform="rotate(0, 55, 240)">0V</text>
<line x1="60" y1="240" x2="470" y2="240" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<text x="145" y="140" style="font-family:Arial;font-size:12px;text-anchor:end" dominant-baseline="middle" transform="rotate(0, 145, 140)">+5V</text>
<line x1="150" y1="140" x2="160" y2="140" style="stroke:rgb(0, 0, 0);stroke-linecap:square;stroke-width:2" />
<ellipse cx="390" cy="240" rx="2" ry="2" style="fill-opacity:1;fill:rgb(0, 0, 0);stroke:rgb(0, 0, 0);stroke-width:2" />
<ellipse cx="340" cy="240" rx="2" ry="2" style="fill-opacity:1;fill:rgb(0, 0, 0);stroke:rgb(0, 0, 0);stroke-width:2" />
<ellipse cx="390" cy="160" rx="2" ry="2" style="fill-opacity:1;fill:rgb(0, 0, 0);stroke:rgb(0, 0, 0);stroke-width:2" />
<ellipse cx="310" cy="240" rx="2" ry="2" style="fill-opacity:1;fill:rgb(0, 0, 0);stroke:rgb(0, 0, 0);stroke-width:2" />
<ellipse cx="170" cy="140" rx="2" ry="2" style="fill-opacity:1;fill:rgb(0, 0, 0);stroke:rgb(0, 0, 0);stroke-width:2" />
</svg>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

View File

@@ -9,7 +9,7 @@ export const SITE: Site = {
ogImage: "astropaper-og.jpg", ogImage: "astropaper-og.jpg",
lightAndDarkMode: true, lightAndDarkMode: true,
postPerIndex: 4, postPerIndex: 4,
postPerPage: 3, postPerPage: 5,
scheduledPostMargin: 15 * 60 * 1000, // 15 minutes scheduledPostMargin: 15 * 60 * 1000, // 15 minutes
showArchives: true, showArchives: true,
}; };

View File

@@ -0,0 +1,75 @@
---
pubDatetime: 2025-09-28T00:00:00Z
title: Adding Smarts to a Dehumidifier
draft: false
tags:
- code
- esphome
- homeAssistant
- electronics
description: Adding notifications to our dehumidifier
---
Recently we bought a small dehumidifier to try and keep the moisture levels under control in our basement. We went with a fairly cheap one just to see how we'd get on with it. Amazon let us know that it was a frequently returned item, so that really inspired confidence.
![](../../assets/images/dehumid/dehumid.jpg)
It's been running for a few weeks now, slurping up moisture out of the air, and it seems to be working perfectly. The only issue we have is that we tend not to notice once it fills with water and shuts itself off as we don't use the basement that frequently.
Obviously this is the sort of issue that could be solved by just checking on it more frequently, but I've been wanted to get my soldering iron out again and this seemed like the perfect oppurtunity.
## Hardware
I rummaged through my drawers to find something suitable and came across a Beetle-esp32-c3 that I had left over from another project. I knew that the software side would be fairly simple with ESPHome and Home Assistant, and I thought the hardware would be similarly easy.
![](../../assets/images/dehumid/beetle.jpg)
The hardware side of things took a little longer than I thought it would. There are two leds on top of the unit, one for power and one for 'tank full'. I was assuming that the circuit would look something like the following and that I could just tap off some nice logic signals from the leds.
![What I hoped](../../assets/images/dehumid/circuit.svg)
Unfortunately, that's not how it was designed. Most of the logic is at 9v - high enough to damage my little Beetle. There wasn't even a suitable power supply that I could use. Fortunately, I had some spare buck regulators from the same previous project that could safely take the 9v power down to 5v for the Beetle, but that still left the issue of figuring out how best to tap in to the circuit...
In the end I took inspriration from Big Clive and drew myself a schematic as I beeped out the circuit, and rummaged through online datasheets.
![](../../assets/images/dehumid/schematic.jpg)
I left out a lot of the wiring that wasn't relevant - like how the momentary switch latches the power, and how it won't do anything unless the bucket is inserted - but eventually I understood roughly how it worked, and how I could interact with it.
The VCC output of the microcontroller was only high when the machine was running, and it was ~4.5V - a nice level for the Beetle to read. The tank full light was switched on the low side when activated. This meant that I could use a pin on the Beetle with a built-in pullup resistor to stay high normally, and be pulled to ground with the led when activated. Nice!
![](../../assets/images/dehumid/closeup.jpg)
![](../../assets/images/dehumid/overview.jpg)
## Software
As I mentioned earlier ESPHome makes this really super simple. The config for the Beetle is as follows (standard wifi stuff removed):
```yaml
binary_sensor:
- platform: gpio
pin:
number: 7
inverted: true
mode:
input: true
pullup: true
filters:
- delayed_on: 2s
name: "Tank full"
- platform: gpio
pin: 2
name: "Running"
```
That's it. That's all it takes for this to appear in Home Assistant
![](../../assets/images/dehumid/has.png)
From there it's a simple matter to set up some automations to get alerted once the bucket is full
![](../../assets/images/dehumid/alert.png)
## Conclusion
It's really wonderful to see how easy it's become to do this sort of thing.

View File

@@ -7,10 +7,10 @@ const getSortedPosts = (posts: CollectionEntry<"blog">[]) => {
.sort( .sort(
(a, b) => (a, b) =>
Math.floor( Math.floor(
new Date(b.data.modDatetime ?? b.data.pubDatetime).getTime() / 1000 new Date(a.data.modDatetime ?? a.data.pubDatetime).getTime() / 1000
) - ) -
Math.floor( Math.floor(
new Date(a.data.modDatetime ?? a.data.pubDatetime).getTime() / 1000 new Date(b.data.modDatetime ?? b.data.pubDatetime).getTime() / 1000
) )
); );
}; };

View File

@@ -2454,17 +2454,10 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"caniuse-lite@npm:^1.0.30001646, caniuse-lite@npm:^1.0.30001688": "caniuse-lite@npm:^1.0.30001646, caniuse-lite@npm:^1.0.30001663, caniuse-lite@npm:^1.0.30001688":
version: 1.0.30001692 version: 1.0.30001745
resolution: "caniuse-lite@npm:1.0.30001692" resolution: "caniuse-lite@npm:1.0.30001745"
checksum: 10c0/fca5105561ea12f3de593f3b0f062af82f7d07519e8dbcb97f34e7fd23349bcef1b1622a9a6cd2164d98e3d2f20059ef7e271edae46567aef88caf4c16c7708a checksum: 10c0/646ca4b57baaa7a835cf7204c8a257490ee8e36364c04638212e3750c5e8ef45c39f352307e6205114487bcc179d42f5216f6dac146641b16a60b20b29d6f2a6
languageName: node
linkType: hard
"caniuse-lite@npm:^1.0.30001663":
version: 1.0.30001667
resolution: "caniuse-lite@npm:1.0.30001667"
checksum: 10c0/6bc8555a47603e1e76eaef9b185d6fdeeca7d9c20a283f7c32c971eb1b52ea3a80e6ec086920f088f06abe619240f1023a2d3a08b5b1f2f11df1475695e9f71c
languageName: node languageName: node
linkType: hard linkType: hard