Previously, I tested an Atomic PI* with Clear Linux* (See: Clear Linux* OS on an Atomic Pi!) and since then I’ve actually done something interesting with the board that falls into the category “Yeah, that’s what it’s actually designed for”.

There’s some credits at the end and some disclaimers, please read.

Introducing the Atomic Chicken Coop PI

My family built a chicken coop recently. We got the chickens a while back and recently they were big enough to go into it, so I was coaxed to come up with a solution for allowing the chickens to come out early in the morning in the weekends. Preferably automatic. As things go you can nowadays buy entirely automated systems for this but they aren’t cheap and most of them require power, something that our coop doesn’t have, simply because to do it within code would be too expensive.

It started with some basic plans.

So I gave myself a budget and went out and investigated if I couldn’t make the Atomic PI do this and run entirely on solar power. That wouldn’t be cheap for something that just opens and closes a door, per se, but it would also have the opportunity to e.g. include a webcam, tweet when there’s new eggs, count chickens, alert if predators were in the hen house, etc… In other words - it would be useful and give us some fun experiments.

Having tested the Atomic PI before I knew the power draw was 4-5W idle, so I could do my solar power calculation and battery estimates pretty well, but it would still be highly dependent on many factors. I set out to use some basic math and used some of the online calculators to determine what panel size and battery size I would need and how long they would last in case there was no sun. In the end, I settled for a 12V 50W panel and 12V 20Ah battery, knowing that I’d likely only get 10-15W out of the panel most of the time, and the battery shouldn’t be drained below 50%.

I picked up a very cheap solar charge controller that was 10A. More than plenty for the use case, since, I’d be doing 1A or so or less most of the time. A cool feature for this charge controller was that it has an RS232 output port, but I had no idea about the protocol or even how to hook it up to the Atomic PI just yet, but, these controllers are cheap enough that it was worth the bet anyway.

The Door

The biggest issue isn’t electrical here: How do you open the door. It’s a mechanical problem, not an electrical one, really. First, you must exert enough force to open the door, but, not enough to crush a chicken. Second, chickens are messy, so, expect that the door may not be closing exactly. You also want to make sure you know when the door opens, is open, and doesn’t jam mid way. This is entirely a civil engineering thing, and not a software engineering problem.

You could solve this with a stepper motor and “roll up a coil of rope” But rolling up a cord has wear issues and the rope can get tangled. You can do a stepper motor and a worm thread, but, the mechanical part of mounting a worm thread and a heavy chicken coop door don’t really work well and I foresaw wear and tear would quickly cause the door to fail. Not an attractive solution.

Enter, the piston.

Yes! That’ll do it!

I found, while browsing for parts, a very interesting solution. Essentially it’s a motor with a heavy duty wormthread, encased in metal, with on/off sensors. These are made for “furniture” application and are meant to lower/raise chairs or support. You can get them in various sizes and they are … really not very expensive considering they are absolutely heavy duty. They have weight ratings in the 1000lbs or so.

This seemed ideal for the job - I needed to open the ~20" door gap and there was a 20" version of this lineair actuator available. To make sure I wasn’t going to crush a chicken, I put a rope between the actuator and the door - this made it so that when the door is closing, if a chicken decides to nap in the doorway, the door will lower but only the weight of the door would rest on the chicken, and not the full 1000lbs force of the actuator. It also allowed me to mount the actuator away from the floor of the coop and away from the chickens, since the ceiling would likely be the safest place to mount stuff.

Automation

The end result had certain “requirements” - the family should be able to use it, so, it can’t require an SSH terminal and manual bit banging. So, I decided to plan to intergrate everything to work with homeassistant from the domotica bundle. This means that I needed to build a small software stack to deal with GPIO’s, serial IO, and transport it over a WIFI connection into hass . The obvious solution for the transport was to use MQTT .

I really hate writing python code for embedded/system level code, so, I made sure to package or get packaged libmodbus , libpgiod , mosquitto , homeassistant and for good measure use libconfig . Now I had all the software libraries available to hopefully build a software stack that could control and monitor the state of the Atomic PI IO ports and allow me to interact with it over the network connection.

Construction

Mechanically, it all worked out really well in the end. The solar panel fits nicely on the south-sloping roof and while not at a perfectly optimal angle it pulls 35-40W at peak levels. The cable runs through the roof with a watertight seal/cap to the solar charge controller. I stuck the battery in a separate box outside the coop in case of fumes/gassing, but the low amperage to/from the battery should make it relatively safe, it’s also a sealed lead-acid so the risk is a bit less.

The battery and the Atomic PI are on the same circuit. I am not using the load side of the solar charge controller (yet), since my linear actuator pulls quite a bit of power (2.5A) when it operates. I had to get a 12V-5V voltage downstepper to get power to the PI. To make things easy to control the motor forward/reverse, I bought a simple motor forward/reverse relay board that has a programmable timer. You simply trigger it momentarily, and it makes the motor go forward or backwards for a specificed amount of time. Ideal for my application.

I also purchased a RS232 to TTL converter module in an attempt to talk to the solar charge controller. The manufacturer only advertises a bluetooth dongle, but, I found that someone posted a node module for a similar device from the same manufacturer. Because I’m not a shy person, I sent an email to the manufacturer’s technical contact address asking for the pinout for the RS232 port, figuring that I could just reverse engineer everything else since the node module had most of the data. Instead, the technical support mailed me the full MODBUS INTERFACE SPECIFICATION. Oh well, that’s even better, but, I was actually asking for the pin assignments. heh. In the end, I just opened up the charge controller and used a cellphone to snap a picture of the layout and the RS232 IC, which allowed me to figure out that pin 1 & 2 were RX/TX, and 3 & 4 were GND.

Then it was just a matter of wiring up GPIO’s, resistors, heatshrink, screw terminals, etc… All of that is straightforward enough! Ahem, well, maybe.

Electrical

Wiring isn’t too complex in this project but wire gauge is important - the Atomic PI for instance requires enough power that you can’t use a single pin header for power delivery. However, I also wanted to use 3.3V on the board to drive GPIO’s and the standard Atomic PI has only 5V on it and no breakout for 3.3V. So, I ended up working on my “whole enchilada” board directly and despite it being meant for “prototying”, it’s what actually will go into the chicken coop. That means I just soldered to the enchilada for my pull ups/downs and Serial-to-TTL converter stuff.

For the solar panel, I had no issues as the solar panel comes with wires and 4mm^2 cabling, I just bought a 3ft terminal cable set that plugged in to the panel connectors so I could drive those through the roof.

Between the PI, the battery, and the solar charge controller, I ended up reusing some old 14AWG solid wire I had laying around. It’s rated 15A (at 130V) and sufficient for the 2-3 feet lengths I have. I ended up buying some automotive fuses that are in-line to put some 10-15A fuses in between things to make sure chickens won’t be witnessing unexpected fireworks, hopefully.

On the computer side, I added 2 switches to enable the 12V circuit (which has all the manual control and relay power) and the 5V output to the Atomic PI. This allows me to turn off the Atomic PI entirely while still powereing the relay motor control board and use push buttons. Yeah, the kids love this part. The manual push buttons wire up to the relay board. There’s additional wires to 2 GPIO pins here with pullups/downs so that the Atomic PI can trigger them as well.

The RS232 to TTL wiring is similarly very simple. 2 pins to GPIO’s that are preset for RX/TX serial on the Atomic PI and 3.3v/GND, and you’re set.

Rough wiring layout before I figured out this wouldn’t fit. At all. Oops.

It’s starting to come together now!

Now that I’ve had everything kinda wired up roughly, I could start writing my software and figure out the “logic layer”.

GitHub sofar/coop-uter A collection of tools written for my chicken coop automation project - Atomic PI system, Renogy solar charge controller with MQTT interface. - sofar/coop-uter

All the code I wrote is in the above project.

libgpiod

The libgpiod library is a relatively new way to that uses file descriptors to interface with the 4 GPIO IC’s on the Atomic PI. It is a structurally much better way to do GPIO than the old sysfs method. In essence, the whole thing is trivial - you just set a line to high or low . Electrically, it gets really confusing since you want to make sure you don’t put 5V into your GPIO since it’ll fry it, and that’s the end of the GPIO pin. So, we use some pull down/up resistors in a few places, to make sure we’re current limiting and not creating smoke. But, on the logic side, it’s bizarrely trivial.

First, I wired up the motor control pins to GPIO1&2, since, they haz kewl LED lights! I figured I’d be able to see the trigger signals and frankly, they’re too cool not to use.

Atomic PI GPIO pins on the breakout header and their addresses.

I reserved GPIO 3 & 4 for future door sensors, which would leave me another 2 free GPIO pins for later, maybe for a temperature sensor or light sensor or something.

github.com sofar/coop-uter/blob/master/door.c#L209 return; } fprintf(stderr, "Closing door

"); command = true; command_time = time(NULL); state = 3; publish_state(mosq); // perform the change gpiod_ctxless_set_value("3", 24, 1, true, GPIOD_CONSUMER, usl, NULL); gpiod_ctxless_set_value("3", 24, 0, true, GPIOD_CONSUMER, usl, NULL); } else if (((char *)message->payload)[0] == '1') { // open if ((state == 2) || (state == 1)) { // already opening or open return; } fprintf(stderr, "Opening door

");

it just takes 1 line of C to change a GPIO line.

25ms Is already enough to trigger the relay board and drive the door open. You can experiment with gpioset from the commandline as well until you get it working.

The door sensors are similarly simple, just read the GPIO line when you want. I didn’t make an interrupt or setup libpgiod messaging just yet, but, that should be just as easy to have it tell you when the line changes.

github.com sofar/coop-uter/blob/master/door.c#L78 // 2 minute intervals between normal idle publishes #define CHECK_INTERVAL 150 static void sigfunc(int s __attribute__ ((unused))) { stop = 1; } static void get_sensor_data() { int closed = gpiod_ctxless_get_value("3", 22, true, GPIOD_CONSUMER); if (closed < 0) { fprintf(stderr, "gpiod sensor read 15: %d

", closed); state = 4; } else { sensor_closed = closed; } int open = gpiod_ctxless_get_value("3", 15, true, GPIOD_CONSUMER); if (open < 0) { fprintf(stderr, "gpiod sensor read 22: %d

", open);

Reading the door position with 2 sensors - a simple way to see that the door is properly opened, closed or somewhere half way.

libmodbus

The modbus protocol is a serial protocol that allows many devices to talk over an RS232 line. Basically, every device assumes an address and when requests are made on the line, the address indicates which device should talk back. In the case of a single device, it will take address 1 .

The RS232-TTL logic level converter, happily wrapped in electrical tape to hide my shameful soldering technique.

After I hooked up the Atomic PI using the TX/RX pins on the breakout header and the 3.3V line available on the enchilada board, I could already chat with the device using simple modbus commands so I wrote a little dump script to just read out the various data that is exposed.

The whole breakout header has 2 serial TTL RX/TX pairs that bind to /dev/ttyS* device nodes.

github.com sofar/coop-uter/blob/master/dump.c#L56 if (modbus_connect(ctx) == -1) { fprintf(stderr, "Connection failed: %s

", modbus_strerror(errno)); modbus_free(ctx); exit(EXIT_FAILURE); } /* identify the charge controller */ uint16_t regs[64]; memset(regs, 0, sizeof(regs)); ret = modbus_read_registers(ctx, 0x0c, 0x08, regs); if (ret < 0) { fprintf(stderr, "Failed to read registers: %s

", modbus_strerror(errno)); modbus_free(ctx); exit(EXIT_FAILURE); } fprintf(stderr, "Model: \"%s\"

", (char *)regs); /* software/hardware version */ memset(regs, 0, sizeof(regs));

Modbus - Incredibly simple from a software perspective

I don’t think I spent more than 15 minutes on this - this is really really easy. The spec given to me describes all the registers and I just read them with 1 command into a simple array. Done, I could read all the basic panel voltage, battery level, etc. stats and I still had enough time to play Idle Apocalypse a bit. I mean, debug my code.

github.com sofar/coop-uter/blob/master/publish.c#L100 /* read info block regs */ memset(regs, 0, sizeof(regs)); ret = modbus_read_registers(ctx, 0x100, 0x22, regs); if (ret < 0) { fprintf(stderr, "Failed to read registers: %s

", modbus_strerror(errno)); modbus_free(ctx); exit(EXIT_FAILURE); } /* create mqtt publish stream */ int battery_capacity = regs[0]; float battery_voltage = regs[1] / 10.; float battery_current = regs[2] / 100.; int controller_temperature = (int8_t) MODBUS_GET_HIGH_BYTE(regs[3]); float load_voltage = regs[4] / 10.; float load_current = regs[5] / 100.; int load_power = regs[6]; float panel_voltage = regs[7] / 10.;

The one thing I need to watch: battery level!

I’m a stat junkie, but, monitoring the battery level is pretty critical - this unit is completely relying on the battery working and not draining below ~50% because it drastically limits the llfespan of the battery. So, if we have to, we need some way to do an emergency shutdown of the system when the battery level is too low.

Now, this wasn’t the only protection I built into the system. I also had purchased a 12V undervoltage cutoff protector. However, after mucking with this for a long time, I found it to be way too easy to trigger the 10V undervolt level because the switching time of it was … microseconds. And of course, the 2.5A lineair actuator totally drops the voltage down very, very hard for a very short time. So, I had to ditch that component - even with some extra capacitors I couldn’t make it attenuate the voltage drop enough for it to not power off the Atomic PI every morning.

The problematic undervoltage protector - I’m sure this would work great if I hadn’t chosen a Minetest Piston.

Mounting

Of course, plans are great but I had to redo all the wiring almost. It still turned out pretty neat and tidy in the final install location.

It all looks so simple. Haha, nope.

Here’s the “end result” as far as mounting goes. There’s a cage protecting the CPU from chicken attacks but giving it plenty air. The solar charge controller is neatly tucked to the ceiling, and the piston/pulleys transfer the arm movement to properly lift the door up straight which makes it slide nice and easy. The door sensors can also be seen here - the “door open” one, that is. You can see the wiring for the “door close” sensor too. I taped the antenna for the wifi to the wall so that I can easily take the cage off to do maintenance.

Uhh, honey I dropped the ladder.

“No, you can’t press the buttons again, you already opened and closed it 4x now. Do you understand duty cycle?.”

Here’s the manual control on the side of the coop. These are 1$ mechanical switches from your favorite super market grocer. Trust me, the wooden box cost me several hours to make, and was a major ordeal.

GUI

All things said, now I could SSH and speak MQTT, but, the family does not speak these languages. So the last mile of this is to integrate it in homeassistant.

We do this by exporting the status and control over MQTT. I have a WIFI land that the coop can access and is fairly reliable, so, we can talk to the coop and send it messages, and it can send updates over it’s state. This is what mosquitto does for us.

github.com sofar/coop-uter/blob/master/door.c#L307 } ret = mosquitto_subscribe(mosq, NULL, topic_control, 0); if (ret != 0) fprintf(stderr, "mosquitto_subscribe: %d: %s

", ret, strerror(errno)); fprintf(stderr, "connected, state topic = %s, control topic = %s

", topic_state, topic_control); for (;;) { ret = mosquitto_loop(mosq, 5000, 1); if ((ret == MOSQ_ERR_CONN_LOST) || (ret == MOSQ_ERR_NO_CONN)) { sleep(5); mosquitto_reconnect(mosq); } else if (ret != MOSQ_ERR_SUCCESS) { fprintf(stderr, "mosquitto_loop(): %d, %s

", ret, strerror(errno)); exit(EXIT_FAILURE); } get_state(); publish_state(mosq);

This is probably the most complex part of the code. You’ll need to understand mainloop event handling and make sure you’re not sending too many messages, think about idle times to save power and properly reading state. I certainly didn’t do a good job yet but it works, somewhat and it’s better example code of libmosquitto than I’ve seen anywhere else (it’s like… nobody uses this…).

The neat thing about it is that you can then go straight to homeassistant and just bang your devices into the config:

cover: - platform: mqtt name: "Coop door" command_topic: "/cooper/door/control" retain: true payload_open: "1" payload_close: "0" payload_stop: "q" sensor: - platform: mqtt name: "Coop door" state_topic: "/cooper/door/state"

And wow, it works, I can do this now:

Ok, I’m lying, there’s like 10 sensors in that view.

The nice thing is that hass gives me some pretty basic, but really useful basic statistics/charts:

hass creates a ton of graphs that can help to monitor and change usage. Ultimate, I’ll have hass automatically open and close the coop door based on outside light.

Wrapping it all up

I’ve built a pretty expensive coop door opener. It’s only reasonably priced because the base price of the Atomic PI being a ridiculous $35. However, you could likely get this far with an ESP8266 as well and considering the power draw of that unit, you could go a lot smaller on the panel, battery and thus budget. To me, the cool thing is that now I’m running an x86_64 that’s capable, and happily running clearlinux and I can move to the next parts of the experiment: Object recognition.

The Atomic PI kit I bought comes with 2 USB webcams that give you a 1080p frame. It’s reasonably sharp and I want to use it to try and (1) count eggs once the chickens start laying. That way the family can get a notification when there’s enough eggs to pick up. I also want to see if I can count chickens coming in and out of the coop, so, there’s some sort of confirmation that they are all inside.

Additionally, perhaps exporting the webcam over ONVIF or RTSP with GPU accelerated h264 encoding would be nice, so that it doubles as a security camera.

Thus far, everything “works”. There are still some major issues with the amount of power available. Now that fall started we’re seeing some days where I get 2-3 Ah of sunshine power, which is just barely enough. I’ve been experimenting with rtcwake to make the system sleep in s0 and wake up by RTC clock. That drops the power consumption from 4W down to 1.7W - a huge chunk of power, but not all the software I wrote is happy with that just yet.

I’ll do another write up when I add some significant sections to this “build”.

Can we go in it yet? Is it done? (Foto credit: Stacey Serafin)

Credits

I’d like to thank Brett Warden explicitly for all the help I had - this was the first time in 15 years that I’ve had this much fun with electronics and having Brett around to make sure I’m not frying everything totally helped me to do this with almost no frustration whatsoever - this was incredibly fun to do and I owe him a couple of boxes of fresh eggs at least. Of course, there’s a few others not mentioned in here that have done way more on this coop project than me. Also everyone who listened to my silly chicken coop stories in the office - I’m sorry! Photography is my own unless stated otherwise. Minetest is CC-BY-SA. The coop plan rendering is a render example of the actual coop plans used. The chickens are from eggs.

disclaimers

Obligatory: While I work for Intel/Clear Linux - the coop project was a personal project and all materials were purchased by myself, and code was written in my own time at home. While I did use Clear Linux for everything, I used stock/public available Clear Linux code. All the code I wrote for this is on the github link at the top and licensed MIT as I consider it example code quality only (NO WARRANTY). Intel did not sponsor this project. Opinions stated in this article/blog are purely my own. DLI and Renogy* and other component manufacturers used for this project did not sponsor or pay for this blog post. This article is not an endorsement for any of the projects mentioned. Other names and brands may be claimed as the property of others. The story, all names, characters, and incidents portrayed in this production are fictitious. No identification with actual persons (living or deceased), places, buildings, and products is intended or should be inferred. I’m sure I’m forgetting some disclaimers here.