my website

add blog/2026-01-09-weather-station-0, minor style changes

+237 -2
+220
src/blog/2026-01-09-weather-station-0/content.djot
··· 1 + I'm making a weather station because they're really cool. I've always wanted one, idk why exactly. 2 + But they're just _cool_ to me. Meteorology is cool too. 3 + ([Holy shit there are _so_ many kinds of clouds.](https://en.wikipedia.org/wiki/List_of_cloud_types)) 4 + 5 + So ANYWAYS, 6 + 7 + ## The Computer 8 + 9 + ![A small, square PC motherboard, with a passive heatsink. The PCB has a green soldermask. The two SODIMM slots are both filled with laptop memory modules.](./img/mobo.webp) 10 + 11 + This is an Intel Desktop Board D525MW. It boards desktops. 12 + 13 + It sports an Entire Passively Cooled Two Core Four Thread Intel Atom Something running at a Blazing Fast One Point Eight Gigahertz. 14 + You can't change that, it's locked at 1.8, `/sys/devices/system/cpu/cpufreq` is empty. 15 + The memory speed, you ask. The [Technical Product Specification](https://files.eeep.ee/misc/Intel%20Desktop%20Board%20D525MW%20D525MWV%20Technical%20Product%20Specification.pdf), 16 + which is basically the manual, says this: 17 + 18 + > Support for DDR3 800 MHz, DDR3 1066 MHz, and DDR3 1333 MHz SO-DIMMs 19 + 20 + But then adds this Helpful Note: 21 + 22 + > Note: DDR3 1066 MHz and DDR3 1333 MHz memory will run at 800 MHz 23 + 24 + Fun. 25 + 26 + But I want to use it in this project because since I got it it's been very good at such things as taking space 27 + and collecting dust and because it's also borderline useless for anything else. 28 + And because it'll let me run NixOS without too much struggle. 29 + I mean, any operations involving the Nix store aren't exactly the fastest but screw it, it'll be fiiiine. 30 + Basically it's junk that I'd like to find a use for. 31 + 32 + I dug it out recently, stuck two 1GB RAM sticks in it, managed to install NixOS with a Little bit of struggle 33 + (it thankfully more or less supports UEFI), and then set up Prometheus + Grafana along with node_exporter. 34 + Nothing to really write home about here, it's easy on NixOS, and the wiki has examples. 35 + Holy shit is playing with time series fun though. 36 + It really is unusually fun to watch the temperature of a passively cooled CPU graphed over a few hours. 37 + 38 + When I first started playing with it it would keep complaining about a dead backup battery, and a checksum error, 39 + and the BIOS settings being blank, so I swapped the coin cell out for the first one I could find 40 + and it seems to have shut up about allat for now. 41 + I was also getting random SATA errors in dmesg. Swapped out the cable, seemed to be okay. 42 + But then it would continuously spam the following into dmesg every second or so: 43 + 44 + ``` 45 + ata1: SATA link up 1.5 Gbps (SStatus 113 SControl 310) 46 + ata1.00: configured for UDMA/33 47 + ``` 48 + 49 + [Turns out](https://askubuntu.com/questions/1273679/kernel-is-spewing-ata-link-up-messages-every-second) 50 + this has something to do with link power management. 51 + I've never seen that happen so I'm assuming it's implemented in a weird way on this board. 52 + whatever. Go my oneliner: 53 + 54 + ``` sh 55 + sudo sh -c 'for f in /sys/class/scsi_host/host*/link_power_management_policy; do echo max_performance | tee "$f"; done' 56 + ``` 57 + 58 + And the problem is gone. Why is it linking at SATA 1 speeds, because it _should_ be capable of 3Gbit/s, no fucking clue. 59 + But it seems to at least Run Okay. 60 + 61 + ## the Other Part of This Post 62 + 63 + I got this idea a while ago, that if I were to use only I2C sensors, then I could read them out from a regular x86 computer 64 + running Linux directly. How? 65 + Well inside your PC there's already at least one I2C bus, in the form of SMBus (which is... similar enough for our purposes). 66 + Hell, if you happen to be using an x86 PC right now, your computer still has ISA somewhere inside. 67 + 68 + SMBus connects things like random sensors that may be scattered around the board to the chipset or something, idk exactly. 69 + I2C is also how your computer identifies memory modules through [SPD](https://en.wikipedia.org/wiki/Serial_presence_detect). 70 + There's literally a plain old little 24Cxx-like I2C EEPROM on every RAM stick, address 0x50 and everything. 71 + Some even have temperature sensors too. If you have a laptop, the touchpad is connected either through I2C or PS2. It's legacy shit all the way down. 72 + 73 + These buses are not exactly _accessible_ though. 74 + Enter VGA. And HDMI, and DVI, and DisplayPort (at least in DVI/HDMI mode? I think?). 75 + The way a video source (GPU) supporting those identifies a connected display and its supported modes is by reading its 76 + EDID (Extended Display Identification Data) over DDC (Display Data Channel). 77 + EDID is called Extented because before those two, a VGA display could only signal a very 78 + limited amount of supported modes by pulling the four ID pins in the connector low. 79 + Turns out DDC is just I2C, and the thing that stores the EDID is Yet Another regular ass I2C EEPROM. 80 + You can just wire shit to a VGA port, noone can stop you. 81 + 82 + And people have done it, namely mitxela, who [wired up an I2C OLED to a HDMI port](https://mitxela.com/projects/ddc-oled), 83 + as well as [vimpo](https://github.com/vimpop/) who [did the same](https://youtu.be/6KJpy9DRzfY), 84 + but also went further and [got a character LCD to work through a PCF8574 I2C I/O expander](https://youtu.be/4z_ntKJSg_8). 85 + It's certainly not a new idea, I just don't think I've seen anyone use it for stuff you'd usually use something like 86 + a Raspberry Pi. 87 + 88 + Here's a pinout: (receptacle side shown, if you're wiring a plug up, it's the same order if you look from the back of it): 89 + 90 + ![A VGA port with its pins annotated: pins 5 and 10 are both GND, 9 is +5 volts, 12 is SDA, and 15 is SCL](./img/vga.webp) 91 + 92 + _(Yes, +5V, important: DDC uses 5V logic.)_ 93 + 94 + Try it: You can get all of those buses to appear in `/dev` under Linux by inserting the `i2c-dev` module. 95 + Then using `i2cdetect` from `i2c-tools`, you can list I2C/SMBus adapters with `i2cdetect -l` (as root). 96 + My list looks like this: 97 + 98 + ``` 99 + i2c-0 smbus SMBus I801 adapter at 2000 SMBus adapter 100 + i2c-1 i2c i915 gmbus ssc I2C adapter 101 + i2c-2 i2c i915 gmbus vga I2C adapter 102 + i2c-3 i2c i915 gmbus panel I2C adapter 103 + i2c-4 i2c i915 gmbus dpc I2C adapter 104 + i2c-5 i2c i915 gmbus dpb I2C adapter 105 + i2c-6 i2c i915 gmbus dpd I2C adapter 106 + ``` 107 + 108 + The one with `i915 gmbus vga` is the one I'm after. It'll be different for you. 109 + You can also find the right one under `/sys/class/drm/card*-*/`, check what the symlink named `ddc` is pointing at. 110 + Once you have it, you can scan it by doing `i2cdetect -y 2` (again as root), of course substituting 2 for your adapter number. 111 + If you're doing this to a display, address 0x50 (the EDID EEPROM) should respond, and a few others might too, these, I think, 112 + are addresses used for DDC/CI ("Control Interface"). This is that thing that lets you control stuff like monitor settings from the OS. 113 + 114 + ## to obtain One (1) VGA Connector: 115 + 116 + So let's actually wire up the sensor. The sensor I'll be using for now, one of the two that will end up in the weather station, 117 + is the Sensirion SHT31, a temperature + humidity sensor. 118 + The other sensor is the Bosch Sensortec BMP280 (temperature + pressure), which I won't be using for now 119 + because it runs strictly on 3.3V logic. The SHT31 is fine with 5V. 120 + 121 + I needed a VGA plug. So I thought about That One VGA splitter that I took from school 122 + (they threw it out because the cable was bad. I asked if I could take it, they agreed, so I picked it out of the trash can, lmao), 123 + found it, and started hacking away at it. It was quite the fucking fight, the gummy-ish plastic that these get potted in 124 + is surprisingly tough when there's this much of it. 125 + 126 + While pulling the component of interest out of the sea of plastic, I managed to pull out a few pins. 127 + Great, I said, thinking these were the pins I needed, and started seeking the next best thing I could pull a VGA plug out of. 128 + 129 + I remembered that at one point I had also disassembled a monitor with a fixed VGA cable. I dug the cable out, 130 + and once again started trying to cut it open. I think the stuff over this one was even more annoying. 131 + But I made it, and what I saw, I don't know if I had ever seen before. 132 + 133 + ![A metal shield soldered around the entire back of a VGA plug, and crimped on the cable. There are bits of blue plastic around it.](./img/tomb-1.webp) 134 + 135 + Oh my fucking god. Not only was this going to be hell, it was also covered in some sort of greasy 136 + [Universal Surface Schmoo](https://youtu.be/bomUYpEEgtw?t=220). 137 + 138 + But I persevered, and using a combination of tools, including but not limited to: soldering iron, lighter, 139 + slightly dull scalpel, sidecutters, flat-head screwdriver, I somehow managed to Unseal this fucking Tomb. 140 + I hope I don't get a curse or something, holy shit. 141 + 142 + ![The plug, now with the two halves of the shield off the connector and on the desk, among a whole bunch of other junk. The back of the plug is potted in some kind of hot glue-like stuff. There's also a black piece of plastic directly behind the connector.](./img/tomb-2.webp) 143 + 144 + Behold. 145 + 146 + Also yes, the spots where the wires were crimped? soldered? was hidden by that black plastic piece, and I tried slicing 147 + away the hot glue-like Substance holding them together, but it wasn't long before I sliced some of the cables. 148 + This time it was actually toast, so I gave up. But it was at this moment that I also realized I had been looking 149 + at the previous plug from the wrong side, because the pinout on Wikipedia shows the receptacle. 150 + 151 + ![A VGA plug seen from the front. Three pins, 6, 7 and 8 are missing.](./img/brit-1.webp) 152 + 153 + Pardon the horrible picture, but all of the missing pins were actually related to the actual RGB signals, which I don't need. 154 + 155 + I pulled the other pins I didn't need out and wired up a doohickey: 156 + 157 + ![A goldpin header soldered directly to the pins of the VGA plug, seen from the bottom. The two data pins of note are wired to the leftmost pin and rightmost pin of the bottom row respectively.](./img/brit-2.webp) 158 + 159 + I put a little sliver of kapton tape over the sensor, and soldered the goldpins on: 160 + 161 + ![The back of the little SHT31 breakout board, with the goldpins soldered parallel to (flat against) the board.](./img/sht31.webp) 162 + 163 + (I soldered them on like this so I could then eventually glue the PCB to whatever is going to hold it and have the sensor stick out.) 164 + 165 + I excitedly wired it all together with jumper wires, and then: 166 + 167 + ![The output of i2cdetect -y 2, showing no responses.](./img/fail.webp) 168 + 169 + Nothing. See if you can spot the mistake, because I did pretty quickly. 170 + 171 + I had wired up what was supposed to be SCL to pin 15 and not 14. No big deal, I thought. 172 + But as I was trying to fix it, the _correct_ pin just _had to_ break off. Shit, I might still be able to save it. 173 + And I try pushing the pin out, from the front, and then... the other side breaks off. I tried and tried to Surgically Extract 174 + the broken off pin, to no avail. I broke one of my fucking multimeter probes too. 175 + 176 + At this point I was tired and lowkey pissed off, so I thought it's prime time for a fucking 177 + 178 + [*SACRIFICE*]{style="font-size: 5em;"}. 179 + 180 + ![A black VGA cable on the floor.](./img/sacrifice.webp) 181 + 182 + Chop. Oopsie daisy oh well. I have another one. (That one _is_ also stupidly long but whatever.) 183 + 184 + I quickly stripped the cable, cut the RGB and sync wires short, folded them back, and covered them along with the shielding 185 + with a piece of heat shrink tubing. I was left with four wires. Convenient. 186 + I quickly beeped them out with my multimeter and soldered them up to another header, this time in the same order 187 + as the SHT31 module, so I could plug it in directly. And the result was this: 188 + 189 + ![A short VGA cable ending on one side in a 4-pin header into which the module is plugged in, as described, on the other side plugged into a motherboard.](./img/working.webp) 190 + 191 + Surprisingly tidy. 192 + 193 + ## the linux side 194 + 195 + You could write your own code that just opens the bus device (`/dev/i2c-N`), does the appropriate ioctls and reads and writes, 196 + and it's not exactly hard on its own, but Linux actually has drivers for some I2C devices. 197 + Some of them it can automatically detect, but the proper way is to have either device tree entries for the devices 198 + or something ACPI something something, or from code. I'm not using a Raspberry Pi, and I don't exactly have access to the BIOS, 199 + not in this context anyways, nor to the kernel code, but there's a fourth way. And you can't just modprobe the driver, 200 + it needs to know what address to talk to (and there could be multiple devices using the same driver at the same time). 201 + Turns out, you can [instantiate devices from userspace](https://docs.kernel.org/i2c/instantiating-devices.html#method-4-instantiate-from-user-space) 202 + by doing more or less this incantation: 203 + 204 + ```sh 205 + echo '<driver> <address>' > /sys/bus/i2c/devices/i2c-N/new_device 206 + ``` 207 + 208 + By default, the SHT31 has address 0x44: 209 + 210 + ![The output of i2cdetect -y 2 showing address 0x44 responds.](./img/epic-win-1.webp) 211 + 212 + ...and the driver is called sht3x, so I had to write `sht3x 0x44`. 213 + After I did that, a new directory appeared under `/sys/class/hwmon`, 214 + and I could directly read out the current temperature and humidity: 215 + 216 + ![The command cat /sys/class/hwmon/hwmon2/{temp1_input,humidity1_input} resulting in two numbers: 21004 and 46414.](./img/epic-win-2.webp) 217 + 218 + That's in 1/1000ths °C and 1/1000ths %RH. Success!! 219 + 220 + TODO: the rest of the owl. It's midnight. Stay tuned.
src/blog/2026-01-09-weather-station-0/img/brit-1.webp

This is a binary file and will not be displayed.

src/blog/2026-01-09-weather-station-0/img/brit-2.webp

This is a binary file and will not be displayed.

src/blog/2026-01-09-weather-station-0/img/epic-win-1.webp

This is a binary file and will not be displayed.

src/blog/2026-01-09-weather-station-0/img/epic-win-2.webp

This is a binary file and will not be displayed.

src/blog/2026-01-09-weather-station-0/img/fail.webp

This is a binary file and will not be displayed.

src/blog/2026-01-09-weather-station-0/img/mobo.webp

This is a binary file and will not be displayed.

src/blog/2026-01-09-weather-station-0/img/sacrifice.webp

This is a binary file and will not be displayed.

src/blog/2026-01-09-weather-station-0/img/sht31.webp

This is a binary file and will not be displayed.

src/blog/2026-01-09-weather-station-0/img/tomb-1.webp

This is a binary file and will not be displayed.

src/blog/2026-01-09-weather-station-0/img/tomb-2.webp

This is a binary file and will not be displayed.

src/blog/2026-01-09-weather-station-0/img/vga.webp

This is a binary file and will not be displayed.

src/blog/2026-01-09-weather-station-0/img/working.webp

This is a binary file and will not be displayed.

+10
src/blog/2026-01-09-weather-station-0/meta.json
··· 1 + { 2 + "title": "making a weather station part 0: The Computer & wiring a sensor up to a VGA port", 3 + "date": "2026-01-09", 4 + "tags": ["software", "hardware", "weather"], 5 + "keywords": [ 6 + "ddc", "vga", "i2c", "sht3x", "sht30", "sht31", "linux", "i2c-dev", 7 + "sensor", "weather station", "arduino", "raspberry pi", "diy", 8 + "intel", "desktop board", "d525mw", "atom" 9 + ] 10 + }
+7 -2
src/style.css
··· 51 51 a { color: var(--color-link); } 52 52 a:visited { color: var(--color-link-visited); } 53 53 54 - img { display: block; } 54 + img { 55 + display: block; 56 + max-width: 100%; 57 + } 55 58 56 59 #fops { filter: drop-shadow(0 0 5px #ccc); } 57 60 @media (prefers-color-scheme: dark) { ··· 108 111 padding: 0.2rem 0.4rem; 109 112 } 110 113 111 - .tag[data-tag='test'] { --bg: #f66151; --fg: #000; } 114 + .tag[data-tag='test'] { --bg: #f66151; --fg: #000; } 112 115 .tag[data-tag='software'] { --bg: #8ff0a4; --fg: #000; } 116 + .tag[data-tag='hardware'] { --bg: #dc8add; --fg: #000; } 117 + .tag[data-tag='weather'] { --bg: #99c1f1; --fg: #000; } 113 118 114 119 pre { 115 120 padding: 1rem;