Skip to content

Commit

Permalink
Merge pull request #2 from Snuffy2/Add_Dockerfile
Browse files Browse the repository at this point in the history
Add Dockerfile
  • Loading branch information
snicker authored Nov 8, 2023
2 parents 74a676b + cc3cc9e commit 639504a
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 8 deletions.
21 changes: 21 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
FROM python:3.12-bookworm

ENV MQTT_HOST="127.0.0.1"
ENV MQTT_PORT=1883
ENV MQTT_DISCOVERY_PREFIX="homeassistant"
ENV DEVICE_NAME="JuiceBox"
ENV ENELX_PORT=8047
ENV ENELX_SERVER="juicenet-udp-prod3-usa.enelx.com"
ENV SRC_DEFAULT="127.0.0.1"
ENV DST_DEFAULT="54.161.147.91"
ENV DEBUG=false

RUN pip install --upgrade pip
RUN apt-get update
RUN apt-get upgrade -y
RUN apt-get install -y git curl dnsutils net-tools telnet expect
# RUN apt-get install -y iputils-ping netcat-traditional nano # Used for debugging
RUN git clone https://github.com/snicker/juicepassproxy.git /juicepassproxy
RUN pip install --no-cache-dir -r /juicepassproxy/requirements.txt

ENTRYPOINT /juicepassproxy/docker_entrypoint.sh
86 changes: 78 additions & 8 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,86 @@ This tool will publish Juicebox data from a UDP proxy to MQTT discoverable by Ho

Hopefully we won't need this if EnelX fixes their API!

## Installation
#### It is required that both your JuiceBox and the machine you are running `juicepassproxy` on have internal static IPs on your intranet.

## Docker Compose Installation

### Features
* If JuiceBox Local IP is defined, it will run a telnet script to get the EnelX Server and Port.
* If DST is not defined, it will use `dig` with the CloudFlare DNS (1.1.1.1) to get the IP address of the EnelX Server and avoid a DNS lookup loop.
* If SRC is not defined, it will use `ifconfig` to get the Local IP address of the Docker.

### Instructions

1. Configure your DNS server running on your network (like Pi-hole or your router) to route all UDP traffic from your JuiceBox to the machine running this proxy. Instructions for how to do this will vary by router. [See below](#getting-enelx-server-ips) for instructions on what EnelX Server you need to override.

1. Place the Dockerfile somewhere on your machine.

1. Add the `juicepassproxy` service to your Docker Compose file.

A. Set the `build:` line to point to the location of the Dockerfile.

B. Set `ports:` to the port listed in the UDCP line [below](#getting-enelx-server-ips).

1. Define the applicable environment variables ([*see below for details*](#docker-environment-variables)).

1. Start the Docker container.

### Example Docker Compose
```yaml
version: '3.8'

networks:
default:
driver: bridge
ipam:
config:
- subnet: 172.16.100.0/24

services:
juicepassproxy:
build: ./juicepassproxy
hostname: juicepassproxy
container_name: juicepassproxy
restart: unless-stopped
logging:
driver: json-file
ports:
- 8047:8047/udp
environment:
- JUICEBOX_LOCAL_IP=10.100.50.30
- MQTT_USER=mosquitto
- MQTT_PASS=***
- MQTT_HOST=10.100.200.5
- DEBUG=true
volumes:
- /etc/localtime:/etc/localtime:ro
```
### Docker Environment Variables
Variable | Required | Description & Default |
-- | -- | --
JUICEBOX_LOCAL_IP | **Recommended** | If defined, it will attempt to get the EnelX Server and Port using Telnet. If unsuccessful, it will default to the EnelX Server and Port below.
SRC | No | If not defined, it will attempt to get the Local Docker IP. If unsuccessful, it will default to 127.0.0.1.
DST | No | If not defined, it will attempt to get the IP of the EnelX Server. If unsuccessful, it will default to 54.161.185.130. If manually defined, you should only use the IP address of the EnelX Server and not the fully qualified domain name to avoid DNS lookup loops.
ENELX_SERVER | No | juicenet-udp-prod3-usa.enelx.com
ENELX_PORT | No | 8047
MQTT_HOST | No | 127.0.0.1
MQTT_PORT | No | 1883
MQTT_USER | No |
MQTT_PASS | No |
MQTT_DISCOVERY_PREFIX | No | homeassistant
DEVICE_NAME | No | JuiceBox
DEBUG | No | false
## Manual Installation
1. Clone this repository
2. Use Python 3.10+ (I recommend setting up a virtual environment)
3. Install requirements `pip install -r requirements.txt`
4. Launch by executing `python juicepassproxy.py --dst <enelx IP:port> --host <mqtthost>` (params documented below)
5. Nothing happens!
6. Configure your DNS server running on your network (like Pihole! or your router) to route all DNS requests to EnelX to the machine running this proxy. For me this was `juicenet-udp-prod3-usa.enelx.com`. See below for instructions to determine that.
6. Configure your DNS server running on your network (like Pi-hole or your router) to route all DNS requests from EnelX to the machine running this proxy. For me this was `juicenet-udp-prod3-usa.enelx.com`. See below for instructions to determine that.

### CLI Options

Expand All @@ -35,7 +107,9 @@ options:
--name DEVICE_NAME Home Assistant Device Name (default: Juicebox)
```
### Getting EnelX server IPs
*For **DST**, you should only use the IP address of the EnelX Server and **not** the fully qualified domain name to avoid DNS lookup loops.*
## Getting EnelX Server IPs
To get the destination IP:Port of the EnelX server, telnet to your Juicenet device:
`$ telnet 192.168.x.x 2000`
Expand All @@ -48,8 +122,4 @@ and give a `list` command:
> # 1 UDPC juicenet-udp-prod3-usa.enelx.com:8047 (26674)
```
The address is in the UDPC line- give that an nslookup or other to determine IP
eg juicenet-udp-prod3-usa.enelx.com is currently 54.161.185.130

This may change over time- but if you are using a local DNS server to reroute those requests to this proxy, you should stick to using the IP address here to avoid nameserver lookup loops.

The address is in the `UDPC` line. Run, `ping`, `nslookup`, or similar command to determine the IP. Currently, `juicenet-udp-prod3-usa.enelx.com` is `54.161.185.130`.
66 changes: 66 additions & 0 deletions docker_entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/bin/bash

NOW=$(date +'%x %X')

echo "--------------------------------"
echo "${NOW}: Starting JuicePassProxy"
echo ""

if [ ! -z "${JUICEBOX_LOCAL_IP+x}" ]; then
echo "${NOW}: JUICEBOX_LOCAL_IP: ${JUICEBOX_LOCAL_IP}"
TELNET_STRING=$(/juicepassproxy/telnet_get_server.expect ${JUICEBOX_LOCAL_IP} | grep "UDPC")
retval=$?
if [ ${retval} -eq 0 ]; then
#echo "${NOW}: TELNET_STRING: ${TELNET_STRING}"
ENELX_SERVER=$(echo ${TELNET_STRING} | sed -E 's/(^.*[0-9]+.*UDPC[ ]+)(.*)(:.*)/\2/g')
#echo "${NOW}: ENELX_SERVER: ${ENELX_SERVER}"
ENELX_PORT=$(echo ${TELNET_STRING} | sed -E 's/(^.*:)(.*)([ ]+.*)/\2/g')
#echo "${NOW}: ENELX_PORT: ${ENELX_PORT}"
else
echo "ERROR getting EnelX Server from Telnet. Using defaults."
fi
fi
if [ -z "${SRC+x}" ]; then
SRC=$(ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p')
retval=$?
if [ ${retval} -ne 0 ]; then
echo "ERROR getting Docker Local IP. Using default."
SRC=${SRC_DEFAULT}
fi
fi

if [ -z "${DST+x}" ]; then
DST=$(dig +short @1.1.1.1 ${ENELX_SERVER} | awk '{ getline ; print $1 ; exit }')
retval=$?
if [ ${retval} -ne 0 ]; then
echo "ERROR getting EnelX Server IP. Using default."
DST=${DST_DEFAULT}
fi
fi

JPP_STRING="python /juicepassproxy/juicepassproxy.py --src ${SRC}:${ENELX_PORT} --dst ${DST}:${ENELX_PORT} --host ${MQTT_HOST} --port ${MQTT_PORT} --discovery-prefix ${MQTT_DISCOVERY_PREFIX} --name ${DEVICE_NAME}"

echo "${NOW}: SRC: ${SRC}"
echo "${NOW}: DST: ${DST}"
echo "${NOW}: ENELX_SERVER: ${ENELX_SERVER}"
echo "${NOW}: ENELX_PORT: ${ENELX_PORT}"
echo "${NOW}: MQTT_HOST: ${MQTT_HOST}"
echo "${NOW}: MQTT_PORT: ${MQTT_PORT}"
if [ ! -z "${MQTT_USER+x}" ]; then
echo "${NOW}: MQTT_USER: ${MQTT_USER}"
JPP_STRING+=" --user ${MQTT_USER}"
fi
if [ ! -z "${MQTT_PASS+x}" ]; then
echo "${NOW}: MQTT_PASS: $(echo ${MQTT_PASS} | sed -E 's/./*/g')"
JPP_STRING+=" --password ${MQTT_PASS}"
fi
echo "${NOW}: MQTT_DISCOVERY_PREFIX: ${MQTT_DISCOVERY_PREFIX}"
echo "${NOW}: DEVICE_NAME: ${DEVICE_NAME}"
echo "${NOW}: DEBUG: ${DEBUG}"

if [ "${DEBUG}" = true ] ; then
JPP_STRING+=" --debug"
fi

echo "${NOW}: COMMAND: $(echo ${JPP_STRING} | sed -E 's/(--password )(\<.*\>)(.*)/\1*****\3/')"
eval ${JPP_STRING}
9 changes: 9 additions & 0 deletions telnet_get_server.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/expect

set host [lindex $argv 0]

set timeout 20
spawn telnet $host 2000
expect ">"
send "list\r"
expect ">"

0 comments on commit 639504a

Please sign in to comment.