Raspberry Pi garage door opener: part 7

I received my HAT PCBs that I designed for the garage door opener. I populated one of them and tested all of the outputs as well as the door closed switch inputs. Everything works. Yay! I will continue assembly tomorrow, and possibly test it wired into the garage doors.

Raspberry Pi garage door opener: Part 6

Today I connected the wiring for door activation from the garage door openers to the new screw terminal keystone jacks in the new wall plate in the garage. I also connected the cat5e to the yellow keystone jack. I then installed the new wall plate (stainless steel) into the new wall box. It looks clean and tidy, and I tested the door activation wiring.

I fabricated the remaining part of the rotary encoder mounts from electrial grade fiberglass angle. Both of the rotary encoders are now mounted.

I terminated the POE connection in my Leviton structured media enclosure in the basement. The jack is a yellow Leviton QuickPort, to identify it as needing POE. I used my Rhino labeler to put a heat shrink label on the cat5e cable before I punched it down on the jack. The jack is in a new Leviton 12-port jack panel that I bought to keep my POE jacks separate from non-POE jacks.

I installed the new POE switch in my rack in the basement. I then assembled a short cat5e patch cable and connected the POE switch to my main switch. I then connected one of the POE ports of the new switch to the new jack that leads to the wall plate in the garage. I connected my Raspberry Pi in the garage with a POE splitter. It works fine.

I drilled two more holes in the enclosure for the Raspberry Pi, and installed cable glands. One is for the wires to activate the garage doors, the other is for the cat5e cable. I haven’t decided how I’m going to connect the door switches yet. I’m leaning toward using a single Neutrik speakON 4-pole connector.

Raspberry Pi garage door opener: Part 5

Tonight I finished running cat5e from the new wall plate box in the garage to the basement. This was a difficult, sweaty job climbing around on trusses in the attic with fish tape (it was over 95F during the day today). But it’s done. I will terminate the ends with new jacks tomorrow.

Over this week I did some work on the enclosure for the Raspberry Pi, my HAT, buttons, indicators, POE splitter and jacks. I installed two Neutrik etherCON jacks in the enclosure for the rotary encoders, since those are on the top of the enclosure and I want to keep dust out of the connection. Fortunately the rotary encoder wires are correctly sized to use with a crimped RJ45. The door activation buttons and door status indicator LEDs are installed in the front cover. Everything appears to fit, though I will not receive my custom PCBs until Monday and hence can’t assemble the whole thing until next week.

I am also waiting on some cable glands, keystone inserts for the door activation wiring and the rotary encoder mounting piece I designed (which I ordered from Front Panel Express).

Raspberry Pi garage door opener: Part 4

I ordered brackets of my design from Front Panel Express to mount the rotary encoders.

I ordered Lovejoy couplings and fasteners from McMaster-Carr to connect the rotary encoders to the garage door shafts.

I ordered a Netgear ProSAFE JGS516PE 16-Port Gigabit Rackmount PoE switch with 8 PoE ports (85w total). I’ve been needing a PoE switch for a while, since I want to install a couple of PoE IP cameras. I also ordered 1000′ of yellow Cat5e cable to use for PoE applications. This will make it easy to identify ethernet cables that have PoE in my home, since my others are blue, grey or white. Finally, I ordered a PoE splitter with 5V microUSB output to power the Raspberry Pi.

Raspberry Pi garage door opener: Part 3

I finally submitted my order for prototype PCBs for my Raspberry Pi ‘HAT’ that I’ll be using for my Raspberry Pi garage door opener. In the end I wound up with this:

  • 2 relays, used to activate the doors. These are driven by relay drivers.
  • 2 rotary encoder inputs (A and B for 2 encoders), to allow my FreeBSD rotary encoder driver to determine the position of the doors.
  • 2 closed door switch inputs. I’m using Honeywell magnetic switches here.
  • 2 pushbutton inputs. I want to be able to activate the garage doors when standing in front of my garage door unit (inside the garage near the doors).
  • 4 LED outputs. I’m using a tricolor panel-mount LED indicator for each door, which will show green when the door is closed, flashing yellow when the door is moving, steady yellow when the door is open but not moving, and will flash red whenever the door is activated.

I’m using anti-vandal pushbuttons for the door activation buttons. Not because I need the anti-vandal feature, but because they are flat and not easy to push accidentally. The ones I’m using have blue ring illumination.

I’m using Apem Q-Series indicator LEDs.

The enclosure I’m using at the moment is a Hammond translucent blue polycarbonate box. Probably larger then I need, but it’ll let me house a POE splitter to power the whole thing via power over ethernet.

I still need to finish the mechanical stuff… mainly the mounting and connection of the rotary encoders. I have a drawing for part of it for FrontPanelExpress, but I don’t really need to go that route for myself. The main issue I’m still debating is whether I can come up with something cheaper and lighter than Lovejoy couplings to connect them to the garage doors.

In any event, I believe I have fully functioning backend software and the web interface works fine. Everything is encrypted, and authentication is required to activate the doors.

Raspberry Pi garage door opener: part 2

I have a fully functioning software suite now for my garage door opener. I have been using a small simulator program on the Raspberry Pi to pull the pins up and down (using the pullup and pulldown resistors). Tonight I plugged in one of the actual rotary encoders, and it works fine. And now that I think about it, I don’t really need the optocouplers on the inputs, since I’m using encoders with NPN open collector outputs. All I need to do is enable the pull-up resistors. This is also true for the garage door closed switches. Hence I am going to draw up a second board with a lot fewer components. The component cost wasn’t significant for the board I have now, but it’ll save on my effort to populate the board. By dropping the optocouplers, I will eliminate 15 components. And technically I could probably eliminate the filtering capacitors too since the encoder cable is shielded. That would eliminate 4 more components.

I hate the amount of board space required for the relays, but I need them. I considered using MOSFETs or Darlingtons, but I decided it was just a bad idea to tie the Raspberry Pi ground to my garage door opener’s ground pin. It’d be a recipe for ground loop disasters. The relays keep the Raspberry Pi isolated. I am using relay drivers to drive the relays, which just saves on component count and board space.

I have a decent web interface now, which runs on my web server and communicates with the Raspberry Pi (encrypted). I have yet to implement the separate up/down logic, but since the web interface shows the movement of the door, it’s not strictly necessary. Door activation works, and I can see whether the door is opening or closing.

My code on the Raspberry Pi will learn the door travel from a full open/close cycle, so the graphic in the web interface is very representative of the amount the door is open.

rotary encoder driver for FreeBSD on Raspberry Pi

I’m working on a rotary encoder driver for FreeBSD 11.0 on the Raspberry Pi.

Why?

I’m tired of consuming CPU to poll GPIO pins for my rotary encoders for my garage door opener project, and as of yet there isn’t a mechanism to deal with GPIO interrupts from user space on FreeBSD. And even with the elegant kqueue mechanism, I don’t really need to push edge interrupts to user space. All I really want is rotary encoder state transitions.

There seems to be a quirk in the setup of GPIO interrupts on the BCM283[56] under FreeBSD. From a very quick scan of the data sheet, I should be able to have separate handlers for rising and falling edges. But FreeBSD doesn’t allow it. Specifically, gpio_alloc_intr_resource() fails for the second interrupt. I have worked around it for now, but I will hopefully find time to revisit this issue later.

I have the interrupt handling working, I tested it using a simple shell script to manipulate the pullup and pulldown resistors. I have two encoders configured since I need one for each of my garage doors.


gpiorotenc0: on ofwbus0
gpiorotenc0: inputs on gpio0 pin 27, gpio0 pin 22
gpiorotenc1: on ofwbus0
gpiorotenc1: inputs on gpio0 pin 23, gpio0 pin 24
...
Jul 4 06:54:48 rpi2 kernel: gpiorotenc0: channel A value 1
Jul 4 06:54:48 rpi2 kernel: gpiorotenc0: channel A value 0
Jul 4 06:54:48 rpi2 kernel: gpiorotenc0: channel B value 1
Jul 4 06:54:48 rpi2 kernel: gpiorotenc0: channel B value 0
Jul 4 06:54:48 rpi2 kernel: gpiorotenc1: channel A value 1
Jul 4 06:54:48 rpi2 kernel: gpiorotenc1: channel A value 0
Jul 4 06:54:48 rpi2 kernel: gpiorotenc1: channel B value 1
Jul 4 06:54:48 rpi2 kernel: gpiorotenc1: channel B value 0

Raspberry Pi garage door opener

In my spare time, I’ve been working on a Raspberry Pi garage door opener project.

The main goal is the ability to open or close my garage door from my iPhone or CarPlay. Unlike the existing projects I’ve seen, my solution has a rotary encoder on each door in addition to a door closed switch. The rotary encoders allow me to see if the door is moving, and hence close or open the door with a single button press. i.e. instead of a direction-ignorant ‘Activate’ button, I can have separate ‘Open’ and ‘Close’ buttons that will do the right thing, even if the door initially moves in the wrong direction. And I can handle two doors with one Raspberry Pi. I could handle more, but I only need it to handle two doors.

Unlike some of the commercial solutions, my solution does not require cloud services. It will still work when my Internet connection is down. If I’m in WiFi range with my phone, I can open and close my garage doors. If my Internet connection is up, I’ll be able to do the same from anywhere in the world.

It is more secure than the average IoT solution. The authentication protocol uses 2048-bit RSA as the base encryption, over which I send an AES256-encrypted randomly generated challenge. The client must decrypt the challenge using their private RSA key, then decrypt the AES256-encrypted challenge with the shared secret key, then encrypt with my server’s public key and send the challenge response. Post-authentication, the session uses AES256. Sessions will typically be short-lived, and we never exchange any secrets. The server will automatically generate a new 2048-bit RSA key each week, which should eliminate the ability of anyone being able to crack the public key crypto and use it in my lifetime (I don’t see a usable quantum computer on the horizon, and the NSA would just break my door down instead of cracking my garage door opener).

I’m nearly done with the server side that runs on the Raspberry Pi. I’m running FreeBSD 11 on the Raspberry Pi, and my server is multithreaded in order to be able to monitor all of the sensors and be responsive to clients at the same time. It is written in modern C++ since that’s been my server language of choice for… 18 years? All unit tests are done for the code that is completed, and I have tested the server with a simple client. I have also tested the sensor inputs, but I’ve yet to send out my piggyback I/O board design for manufacturing. The industrial rotary encoders will arrive soon, so I’ll probably order my PCBs sometime in the next few weeks.

In order to make the iOS side of things easier, client/server messages are encapsulated in JSON. Since I’m using jsoncpp on the server side, it’s trivial for me to write a Qt app for the desktop and a Wt app for my web server if desired since I’d just use jsoncopp in these cases.

Crypto is still ugly to do with Swift, but I’ll manage. I’m going to try to keep my Objective-C and other non-Swift code to a minimum on the iOS side of things.

I intend to allow configuration from a client. The server code to support this is not complete, but the protocol work is in place.

Probably worth noting that I created a separate libDwmAuth project so I can reuse the authentication and encryption in other IoT projects. No cloud needed, no clear text flying around my wired or wireless networks.

creating FreeBSD packages without ports

This weekend I spent some time working on creating FreeBSD packages of my software.

Background…

Way back when, I would use epm. It worked up until FreeBSD switched to pkgng, which was a long time ago. It looks like the author of epm has no interest in updating epm to create native packages on FreeBSD. Probably in no small part because pkgng changed things dramatically. It does make me wonder why epm is still in the ports tree, since its primary facility has not worked on FreeBSD for a long time.

At any rate, pkgng’s ‘pkg create …’ needs a manifest file in order to do what I need. It’s a relatively simple file, though it appears that it’s overly forgiving of missing/present quotes and commas (i.e. the grammar isn’t very rigorous). I’ll blame YAML here.

While I’d like to use libpkg to do what I need, the important data structures are in a private header file. Which presumably means it’s subject to change. And there appears to be no good way to get at the contents of a manifest without using the private header file. Though I’ve yet to look at using libucl to parse a manifest file.

I wrote my own FreeBSDPkg::Manifest class and helper classes, along with a lexer/parser for manifest files using flex and bison. The parser can populate a Manifest object from a manifest file. The manifest can then be manipulated as desired, and emitted to an ostream. For my own software packages, this will allow me to create a skeletal manifest file from the build, then further populate it with my files, then create a native FreeBSD package. What I have today works on libDwm, and the next release of libDwm will include the classes and some supporting applications.

mcblock examples

I recently wrote about the creation of a new utility I created to help manage my pf rules called mcblock. Thus far the most useful part has been the automation of rule addition by grokking logs.

For example, it can parse auth.log on FreeBSD and automatically add entries to my pf rule database. And before adding the entries, it can show you what it would do. For example:

# bzcat /var/log/auth.log.0.bz2 | mcblock -O - 
109.24.194.41        194 hits
  add 109.24.194/24 30 days
103.25.133.151         3 hits
  add 103.25.133/24 30 days
210.151.42.215         3 hits
  add 210.151.42/24 30 days

What I’ve done here is uncompress auth.log.0.z2 to stdout and pipe it to mcblock to see what it would do. mcblock shows that it would add three entries to my pf rule database, each with an expiration 30 days in the future. I can change the number of days with the -d command line option:

# bzcat /var/log/auth.log.0.bz2 | mcblock -d 60 -O -
109.24.194.41        194 hits
  add 109.24.194/24 60 days
103.25.133.151         3 hits
  add 103.25.133/24 60 days
210.151.42.215         3 hits
  add 210.151.42/24 60 days

By default, mcblock uses a threshold of 3 entries from a given offending IP address in a log file. This can be changed with the -t argument:

# bzcat /var/log/auth.log.0.bz2 |  mcblock -t 1 -O - 
109.24.194.41        194 hits
  add 109.24.194/24 30 days
103.25.133.151         3 hits
  add 103.25.133/24 30 days
210.151.42.215         3 hits
  add 210.151.42/24 30 days
31.44.244.11           2 hits
  add 31.44.244/24 30 days

If I’m happy with these actions, I can tell mcblock to execute them:

# bzcat /var/log/auth.log.0.bz2 | mcblock -t 1 -A -

And then look at one of the entries it added:

# mcblock -s 31.44.244/24
31.44.244.0/24     2015/08/21 - 2015/09/20

This particular address space happens to be from Russia, and is allocated as a /23. So let’s add the /23:

# mcblock -a 31.44.244/23

And then see what entries would match 31.44.244.11:

# mcblock -s 31.44.244.11
31.44.244.0/23     2015/08/21 - 2015/09/20

The /24 was replaced by a /23. Let’s edit this entry to add the registry and the country, and extend the time period:

# mcblock -e 31.44.244/23
start time [2015/08/21 04:37]: 
end time [2015/09/20 04:37]: 2016/02/21 04:37
registry []: RIPE
country []: RU
Entry updated.

And view again:

# mcblock -s 31.44.244.11
31.44.244.0/23     2015/08/21 - 2016/02/21 RIPE     RU