Skip to content

ultramcu/v20bits-reader

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

IE-V20Bit-Reader

A Go service for the Orange Pi Zero LTS that reads 20 digital inputs over the on-board I²C and exposes them three ways:

  • a live terminal display
  • MQTT publish-on-change (with a 30 s heartbeat)
  • an embedded web UI for live pin status and editing config.yaml

Hardware

  • Board: Orange Pi Zero LTS
  • Expanders: 3 × MCP23008 (8-bit I/O expander, I²C) on I²C bus 0
  • Default addresses: 0x20, 0x21, 0x22
  • Inputs: 20 active-low digital lines
Pins Expander Bits
1–8 i1 @ 0x20 0–7
9–16 i2 @ 0x21 0–7
17–20 i3 @ 0x22 0–3

Bits 4–7 on i3 are unused. The IODIR register isn't written — MCP23008 power-on default is all GPIO as inputs, which matches the wiring. The code inverts the bit when returning pin state, so a line pulled to GND reads as 1.

How HW access works

The Go code never opens /dev/i2c-* directly. It shells out to an i2cget-compatible binary, configured via app.i2c_bin:

<i2c_bin> -y <bus> <chip-addr> <register>

That indirection exists so the same binary runs on a Mac dev box even though macOS has no I²C. i2cget.sh in this repo is a dummy stub for Mac dev that just echoes 0xAA; with it pointed at by i2c_bin, the display, MQTT publish, and web UI can be exercised end-to-end without hardware.

On the Orange Pi, install i2c-tools and point i2c_bin at the real binary:

app:
  i2c_bin: "/usr/sbin/i2cget"

Configuration

config.yaml (resolution order):

  1. --configPath flag
  2. ENV_CONFIG_PATH environment variable
  3. /root/app/config.yaml if the binary lives in /root/app
  4. ./config.yaml
version: "1"
app:
  box_id: "R0001"
  i2c_bin: "/usr/sbin/i2cget"
  devices:
    - { name: i1, address: 0x20, hardware: 0 }
    - { name: i2, address: 0x21, hardware: 0 }
    - { name: i3, address: 0x22, hardware: 0 }
  mqtt:
    host: "tcp://broker.example"
    port: 1883
    username: "user"
    password: "password"
    publish_topic: "v24reader"
    subscribe_topic: "v24reader"
  web:
    enabled: true
    bind: "127.0.0.1:8080"

hardware is the I²C bus number passed to i2cget -y.

Build / deploy

compile.sh cross-compiles for ARMv7 Linux and optionally scps the binary to the Pi:

./compile.sh                                              # build only
./compile.sh put                                          # build + scp to root@orangepi:/root/app/
DEPLOY_TARGET=user@host:/path ./compile.sh put            # override deploy target

Local Mac build for development:

go build -o /tmp/v20bit .
/tmp/v20bit

Ctrl-C unwinds cleanly: terminal cursor is restored, MQTT disconnects, web server shuts down.

Web UI

Default bind is loopback only (127.0.0.1:8080). Open http://127.0.0.1:8080 and the page polls /api/pins every 500 ms.

Endpoint Method Notes
/ GET dashboard HTML
/api/pins GET {"box_id","ts","pins":[20]}
/api/config GET raw config.yaml bytes (comments preserved)
/api/config POST replace config.yaml; rejects YAML missing app.box_id or with empty app.devices. Restart required to apply.

To expose on the LAN, change web.bind to 0.0.0.0:8080. There's no auth — keep the box on a trusted network.

MQTT

Publish-on-change with a 30 s heartbeat. QoS 0, no retain. Payload:

{
  "box_id": "R0001",
  "ts": "2026-05-18T10:00:00Z",
  "pins": [1,0,1,1,0,0,0,1,1,1,0,0,0,1,0,0,1,0,1,0]
}

The MQTT client connects in the background and auto-reconnects forever, so the service starts and stays responsive even when the broker is unreachable. Messages published while disconnected are dropped (telemetry semantics — the next sample supersedes the last).

Layout

.
├── main.go                # signal-driven run loop (poll → render → publish)
├── config/                # yaml load + atomic save
├── controller/            # board init, i2cget shell-out, snapshot cache
├── mqttx/                 # paho wrapper, non-blocking connect
├── web/                   # http server + embedded index.html
├── config.yaml
├── i2cget.sh              # Mac dev stub (echoes 0xAA)
└── compile.sh             # GOOS=linux GOARCH=arm GOARM=7 build

About

Go service for Orange Pi Zero LTS that reads 20 digital inputs from 3× MCP23008 over I²C, with MQTT publish and a built-in web dashboard.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors