- add Makefile

- improve README.md
- smaller fixes regarding configuration
This commit is contained in:
Thomas Vogl 2022-12-31 17:04:35 +01:00
parent 586a657674
commit e8c46c43f6
14 changed files with 216 additions and 41 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
install/*

8
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/rpiMqttControl.iml" filepath="$PROJECT_DIR$/.idea/rpiMqttControl.iml" />
</modules>
</component>
</project>

9
.idea/rpiMqttControl.iml Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

35
Makefile Normal file
View File

@ -0,0 +1,35 @@
BINARY_NAME=rpicontrol
GIT_COMMIT=$(shell git rev-list -1 HEAD --abbrev-commit)
VERSION=1.0.0
get:
go get .
build_rpi: get
GOARCH=arm GOOS=linux go build -ldflags "-X main.GitCommit=${GIT_COMMIT} -X main.Version=${VERSION} -X main.Arch=${GOARCH}" -o ${BINARY_NAME} main.go
build_linux: get
GOARCH=amd64 GOOS=linux go build -ldflags "-X main.GitCommit=${GIT_COMMIT} -X main.Version=${VERSION} -X main.Arch=${GOARCH}" -o ${BINARY_NAME} main.go
run:
./${BINARY_NAME} -config rpicontrol.conf.example -log info
build_and_run: build run
clean:
go clean
-rm ${BINARY_NAME}
-rm -fr install
-rm -f rpicontrol-${VERSION}.tar.gz
pack:
mkdir -p install/etc/rpicontrol
mkdir -p install/usr/lib/systemd/system
mkdir -p install/usr/bin
cp rpicontrol.conf.example install/etc/rpicontrol/rpicontrol.conf.example
cp rpicontrol.service install/usr/lib/systemd/system/rpicontrol.service
cp rpicontrol install/usr/bin
tar cfvz rpicontrol-${VERSION}.tar.gz -C "install/" .
deploy:
tar xfvz rpicontrol-${VERSION}.tar.gz -C /
systemctl daemon-reload
systemctl start rpicontrol

117
README.md
View File

@ -1,18 +1,115 @@
Raspberry MQTT Control Raspberry MQTT Control
===================== =====================
Description ## Description
--------------- This is a linux daemon application for Raspberry PI, which receives control commands via MQTT to set GPIO ports of Raspberry.
This is a linux daemon application for Raspberry PI, which receives control commands via MQTT to remotely control IO ports of Raspberry. As MQTT is widely supported within different home automation systems, this daemon application should be quite easily be integrated, for example in [OpenHAB](https://www.openhab.org/)
Application is fully configurable with YAML config file. For further information, how to configure and use OpenHAB MQTT Binding, please see [here](https://www.openhab.org/addons/bindings/mqtt.generic/)
## Usage
This application is fully controlled via MQTT Pub/Sub mechanism.
- To test the behavior, install and start an MQTT broker the linux daemon *rpicontrol*, as described in chapter _Installation_.
- As soon as everything is running, you can test the switch of output pins via following command:
`mosquitto_pub -h localhost -t /rpicontrol/gpio/out1/control -m ON`
This command will set the configured GPIO pin with name *out1* to state _ON_.
State _OFF_ will also work of course.
- this command refers to example config as described below. If you have configured different pin names, broker address, or topic prefix,
you have of course to adapt the command according to your configuration.
- In order to see current states of all configured GPIO pins, you can subscribe via wildcard to the MQTT topic:
`mosquitto_sub -h localhost -t "/rpicontrol/#" -v`
- Again, this command refers to example config as described below. If you have configured different pin names, broker address, or topic prefix, you have of course to adapt the command according to your configuration.
Installation and Usage
------------------------- ## Installation
tbd. - Install and configure an appropriate MQTT broker either locally or on your network.
for this, the open-source broker [mosquitto](https://mosquitto.org/) will be a good choice.
For installing and configuring mosquitto for your platform, please see the mosquitto docs.
- untar the package tarball with following command:
`sudo tar xfvz -C / rpicontrol-a.b.c.tar.gz`, where _a.b.c_ represents the version of rpicontrol
- use the example config file as initial configuration
```
cp /etc/rpicontrol/rpicontrol.conf.example /etc/rpicontrol/rpicontrol.conf
```
- edit the configuration file `/etc/rpicontrol/rpicontrol.conf` to your needs, see chapter _Configuration_
- reload systemd, enable and start service:
```
sudo systemctl daemon-reload
sudo systemctl enable rpicontrol.service
sudo systemctl start rpicontrol.service
```
## Configuration
### Example Configuration
Configuration file has YAML syntax, and shall have following structure.
Please note that optional values are not needed for configuration, see _Available Parameters_
```
mqtt-config:
broker-address: "tcp://localhost:1883"
connect-timeout-ms: 10000
connect-retry-interval-ms: 10000
max-reconnect-interval-ms: 10000
topic-prefix: "/rpicontrol"
username: "rpicontrol"
password: "my_password"
pin-control-config:
gpio-pins:
- number: 17
name: out1
direction: Output
pull-config: PullOff
send-polling-events: false
send-change-events: true
initial-state: "OFF"
polling-time-ms: 100
```
### Available Parameters
- **mqtt-config**: section for configuring MQTT Broker Connection
- **broker-address**: URL for MQTT Broker. Example Value: "tcp://localhost:1883"
- **connect-timeout-ms**: (optional) timeout in milliseconds for connection
- **connect-retry-interval-ms**: (optional) connection retry interval in milliseconds
- **max-reconnect-interval-ms**: (optional) max connection retry interval time in milliseconds
- **topic-prefix**: (optional) prefix for MQTT topic
- **username**: (optional) username for MQTT connection
- **password**: (optional) password for MQTT connection
- **pin-control-config**: section for configuring GPIO Pins that shall be used
- **gpio-pins**: list of GPIO pins
- **number**: number of GPIO pin, see [Raspberry Pi: GPIO - General Purpose Input Output](https://www.elektronik-kompendium.de/sites/raspberry-pi/2002191.htm)
- **name**: custom name for the pin (used for MQTT topic).
- **direction**: configure GPIO direction. Available Values: Input, Output
- **pull-config**: configure GPIO pull-up/down resistor. Available Values:
- PullDown: pull-down resistor
- PullUp: pull-up resistor
- PullOff: no resistor
- **send-polling-events**: (optional) send pin state via MQTT on every polling event. Available Values:
- true: enable send on polling event
- false (default): disable send on polling event
- **send-change-events**: (optional) send pin state via MQTT on a change event. Available Values:
- true: enable send on change events
- false (default): disable send on change events
- **initial-state**: (optional) set of initial state of output pin at start of application. Available Values:
- ON: initial state set to ON at startup
- OFF: initial state set to OFF at startup
- [not set]: do not set initial state at startup
- **polling-time-ms**: (optional) interval in milliseconds (default: 100), for cyclically polling the current state of all pins.
Compiling
---------
tbd.

2
go.mod
View File

@ -5,12 +5,12 @@ go 1.17
require ( require (
github.com/eclipse/paho.mqtt.golang v1.3.5 github.com/eclipse/paho.mqtt.golang v1.3.5
github.com/sirupsen/logrus v1.8.1 github.com/sirupsen/logrus v1.8.1
github.com/stianeikeland/go-rpio v4.2.0+incompatible
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
) )
require ( require (
github.com/gorilla/websocket v1.4.2 // indirect github.com/gorilla/websocket v1.4.2 // indirect
github.com/stianeikeland/go-rpio v4.2.0+incompatible // indirect
golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0 // indirect golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0 // indirect
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd // indirect golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd // indirect
) )

View File

@ -10,7 +10,7 @@ type Pin struct {
Name string Name string
Direction PinDirection Direction PinDirection
PullConfig PinPull PullConfig PinPull
InitialState PinCommand InitialState *PinCommand
PinHandle HardwarePinInterface PinHandle HardwarePinInterface
SendPollingEvents bool SendPollingEvents bool
SendChangeEvents bool SendChangeEvents bool
@ -37,11 +37,7 @@ func NewPin(config PinConfig) Pin {
p.SendChangeEvents = true p.SendChangeEvents = true
} }
if config.InitialState != "" { p.InitialState = config.InitialState
p.InitialState = PinCommand(config.InitialState)
} else {
p.InitialState = Off
}
return p return p
} }
@ -80,8 +76,11 @@ func (p *Pin) Configure() {
} else if p.Direction == Output { } else if p.Direction == Output {
log.Infof("configuring pin %s (pin no: %d) as Output", p.Name, p.Id) log.Infof("configuring pin %s (pin no: %d) as Output", p.Name, p.Id)
p.PinHandle.Output() p.PinHandle.Output()
if p.InitialState != nil {
log.Infof("set initial state \"%s\" for pin %s (pin no: %d)", p.InitialState, p.Name, p.Id) log.Infof("set initial state \"%s\" for pin %s (pin no: %d)", p.InitialState, p.Name, p.Id)
_ = p.Command(p.InitialState) _ = p.Command(*p.InitialState)
}
} }
p.PinHandle.Detect(AnyEdge) p.PinHandle.Detect(AnyEdge)
@ -92,6 +91,8 @@ func (p *Pin) Configure() {
p.PinHandle.PullDown() p.PinHandle.PullDown()
} else if p.PullConfig == PullOff { } else if p.PullConfig == PullOff {
p.PinHandle.PullOff() p.PinHandle.PullOff()
} else {
log.Errorf("unknown config value \"%s\" for pull-config", p.PullConfig)
} }
} }

View File

@ -5,16 +5,14 @@ type PinConfig struct {
Name string `yaml:"name"` Name string `yaml:"name"`
Direction PinDirection `yaml:"direction"` Direction PinDirection `yaml:"direction"`
PullConfig PinPull `yaml:"pull-config"` PullConfig PinPull `yaml:"pull-config"`
InitialState PinCommand `yaml:"initial-state"` InitialState *PinCommand `yaml:"initial-state"`
SendPollingEvents *bool `yaml:"send-polling-events"` SendPollingEvents *bool `yaml:"send-polling-events"`
SendChangeEvents *bool `yaml:"send-change-events"` SendChangeEvents *bool `yaml:"send-change-events"`
} }
type PinControlConfig struct { type PinControlConfig struct {
GpioPins []PinConfig `yaml:"gpio-pins"` GpioPins []PinConfig `yaml:"gpio-pins"`
PollingTimeMs int `yaml:"polling-time-ms"` PollingTimeMs int `yaml:"polling-time-ms"`
} }
func NewPinControlConfig() PinControlConfig { func NewPinControlConfig() PinControlConfig {

View File

@ -17,7 +17,7 @@ const (
Input PinDirection = "Input" Input PinDirection = "Input"
Output PinDirection = "Output" Output PinDirection = "Output"
PullUp PinPull = "PULL_UP" PullUp PinPull = "PullUp"
PullDown PinPull = "PULL_DOWN" PullDown PinPull = "PullDown"
PullOff PinPull = "PULL_OFF" PullOff PinPull = "PullOff"
) )

14
main.go
View File

@ -10,12 +10,26 @@ import (
"rpiMqttControl/internal/PinControlService" "rpiMqttControl/internal/PinControlService"
) )
var (
Version string = "0.0.0"
GitCommit string = "000000"
)
func main() { func main() {
versionStr := Version + "-" + GitCommit
flagConfig := flag.String("config", "/etc/rpicontrol/rpicontrol.conf", "path to config file") flagConfig := flag.String("config", "/etc/rpicontrol/rpicontrol.conf", "path to config file")
flagLogLevel := flag.String("log", "info", "set log level for console output") flagLogLevel := flag.String("log", "info", "set log level for console output")
flagVersion := flag.Bool("version", false, "output version and exit")
flag.Parse() flag.Parse()
if *flagVersion {
print(versionStr)
os.Exit(0)
}
log.Infof("starting rpicontrol Version %s", versionStr)
if level, err := log.ParseLevel(*flagLogLevel); err != nil { if level, err := log.ParseLevel(*flagLogLevel); err != nil {
log.SetLevel(log.WarnLevel) log.SetLevel(log.WarnLevel)
log.Warnf("could not set log level. %s", err.Error()) log.Warnf("could not set log level. %s", err.Error())

View File

@ -10,5 +10,7 @@ pin-control-config:
name: out1 name: out1
direction: Output direction: Output
pull-config: PullOff pull-config: PullOff
send-polling-events: false
send-change-events: true
polling-time-ms: 100 polling-time-ms: 100

View File

@ -9,15 +9,11 @@ Group=root
Restart=on-failure Restart=on-failure
RestartSec=10 RestartSec=10
startLimitIntervalSec=60
WorkingDirectory=/usr/bin WorkingDirectory=/usr/bin
ExecStart=/usr/bin/rpicontrol ExecStart=/usr/bin/rpicontrol
# make sure log directory exists and owned by syslog # make sure log directory exists and owned by syslog
PermissionsStartOnly=true
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=rpicontrol SyslogIdentifier=rpicontrol
[Install] [Install]