« Back to home

Pimatic and Docker, taking it further

My previous blog explained how to run pimatic using docker on a raspberry pi. This blog will take it a couple of steps further:

  1. create a image with plugins installed
  2. upload the image to dockerhub for later reuse
  3. run the image

Docker allows me to get my homeautomation up and running very quickly. I really like how you can have a complete pimatic installation ready to run under docker. Now I can play around and easily switch back to the docker image that just works.
However my pimatic images (rpimatic1 and rpimatic2) do not contain any additional plugins. Installation of plugins takes time that I normally do not like to spend waiting when a docker image is starting. So I have the need of a dcoker image with just my plugins pre-installed. Also I need to store it somewhere for easy usage. DockerHub is the place-to-be. But let's first create the image.

Create a custom image

  • Create a Dockerfile (for example Dockerfile.rpimatic2master, this is my main pi in the house)
  • Set the base image (for example FROM joshendriks/raspberry-pi2-pimatic:4)
  • The base image comes with pimatic installed, so just add plugins by adding something like: RUN cd /home/pimatic-app && npm install mysql pimatic-homeduino pimatic-mqtt pimatic-ds18b20 pimatic-node-red pimatic-smartmeter-gas pimatic-tplink-smartplug
  • In my case I also need some additional node-red modules: RUN cd /home/pimatic-app/node_modules/pimatic-node-red/node_modules/node-red && npm install node-red-node-mongodb node-red-node-pushbullet node-red-node-smooth
  • To ensure pimatic starts on boot add: ENTRYPOINT ["pimatic.js"]
  • And expose some ports: EXPOSE 80 8000. Port 8000 is used by the node-red plugin.

As a result you will get the following file:

FROM joshendriks/raspberry-pi2-pimatic:4

# Install pimatic modules
RUN cd /home/pimatic-app && npm install mysql pimatic-homeduino pimatic-mqtt pimatic-ds18b20 pimatic-node-red pimatic-smartmeter-gas pimatic-tplink-smartplug 

RUN cd /home/pimatic-app/node_modules/pimatic-node-red/node_modules/node-red && npm install node-red-node-mongodb node-red-node-pushbullet node-red-node-smooth

ENTRYPOINT ["pimatic.js"]

EXPOSE 80 8000  

But is not complete yet. Pimatic is built using coffeescript. (Which has it's use, I guess....) Coffeescript must be compiled to javascript, before running. The good news is that pimtic will do this for you on first start. The bas new is that changes to disk within a docker image are not persisted. This means that this will happen every time the image is started. Onw way around this is starting pimatic once during build of the image.

Start by creating a pimatic config file next to the Dockerfile. The config must at least contain all plugins that were is installed. Only the plugins that are configured will be compiled.
In the Dockerfile before the ENTRYPOINT add a COPY statement to copy the config into the image at the correct location: COPY config.master.json /home/pimatic-app/config.json
Normally pimatic will keep running, but we need it to stop directly after the startup is completed. To do so we need to modify the startup script temporarily:

## Make sure that pimatic will exit when startup is completed
RUN cp /home/pimatic-app/node_modules/pimatic/startup.coffee /home/pimatic-app/node_modules/pimatic/startup.backup  
RUN sed -i "s/initComplete = true/framework.destroy().then( -> exit(0) )/g" /home/pimatic-app/node_modules/pimatic/startup.coffee  

The above will create a backp of startup.coffee and replace initComplete = true by a command to stop the framework directly.
Then pimatic can be started so that it compiles all the coffeescript files:

## Run pimatic
RUN cd / && pimatic.js  

Cleanup the temporary changes:

## Restore startup.coffee and remove it from compiled cache
RUN rm /home/pimatic-app/node_modules/pimatic/startup.coffee  
RUN mv /home/pimatic-app/node_modules/pimatic/startup.backup /home/pimatic-app/node_modules/pimatic/startup.coffee  
RUN rm /home/pimatic-app/node_modules/pimatic/.js/startup.*  

For a complete example see Dockerfile.rpimatic2master and config.master.json

Build the image the usual way:
docker build -t rpimatic2master -f Dockerfile.rpimatic2master .

When you run the image (docker run -p 80:80 -t -i rpimatic2master) you will see that only startup.coffee needs compiling and as a result pimatic starts relatively quick.

Distribute the re-usable image

Using DockerHub is straight forward:
1. Create an account at DockerHub
2. At the command line login using docker login
docker login

Before uploading you need to tag your image. You can do so by running docker tag 815f36e9c37c <you accountname here>/rpimatic2master:latest

To get the Id of your image run docker images.

Next run docker push <you accountname here>/rpimatic2master:latest and wait for the upload to complete. When finished your image is available on docker hub. To update the image on docker hub, just build a new image followed by a tag and push.
docker push

Note that the image does not contain a proper config file. Which id good as changes to the pimatic configuration should not require building a new image each and every time.

Run the image

Use docker-compose the run docker containers. See my previous blog for installation instructions.

On the docker host, create a pimatic config file and the following .yml file:

registry:  
  restart: always
  image: joshendriks/rpimatic2master:0.0.1
  ports:
    - 0.0.0.0:80:80
  devices:
    - "/dev/ttyUSB0:/dev/ttyUSB0"
  volumes:
    - "/home/pi/private-pimatic/config.master.json:/home/pimatic-app/config.json"

restart: always will make the container to start on system boot and restart in case of pimatic.js (e.g. the ENTRYPOINT of the image) stops. devices: allow the container to access the usb port in this case. volumes: links the config file on the docker host so that this file will be used by pimatic.

Finally start the image using:
docker-compose -f pimaticnode.yml up -d