-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 08039e1
Showing
33 changed files
with
3,556 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
build/ | ||
release/ | ||
test/ | ||
wombatt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# docker build -t wombatt --build-arg=ARCH=arm64 --build-arg=OS=lianux --build-arg=TARGETPLATFORM=arm64 . | ||
ARG BUILD_IMAGE=golang:1.21 | ||
ARG BASE=alpine | ||
FROM --platform=$BUILDPLATFORM ${BUILD_IMAGE} AS build | ||
|
||
COPY . /go/src | ||
|
||
ARG TARGETPLATFORM | ||
RUN ARCH=$(echo $TARGETPLATFORM |cut -f2 -d/);OS=$(echo $TARGETPLATFORM |cut -f1 -d/); \ | ||
cd /go/src; CGO_ENABLED=0 GOOS=${OS} GOARCH=${ARCH} go build -ldflags "-s -w" | ||
|
||
FROM --platform=${TARGETPLATFORM} ${BASE} | ||
COPY --from=build /go/src/wombatt /wombatt | ||
# 20 is the dialout group that gives access to serial ports. | ||
RUN echo "wombatt:x:1001:20::/:/bin/nologin" >> /etc/passwd | ||
USER wombatt:dialout | ||
ENTRYPOINT ["/wombatt"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright © 2023 Gonzalo Paniagua Javier <[email protected]> | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in | ||
all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
MODULE = $(shell $(GO) list -m) | ||
DATE ?= $(shell date +%FT%T%z) | ||
VERSION ?= $(shell git describe --tags --always --dirty --match=v* 2> /dev/null || \ | ||
cat .version 2> /dev/null || echo v0) | ||
PKG = | ||
PKGS = $(or $(PKG),$(shell $(GO) list ./...)) | ||
BINARY = wombatt | ||
|
||
GO = go | ||
TIMEOUT = 15 | ||
V = 0 | ||
Q = $(if $(filter 1,$V),,@) | ||
M = $(shell if [ "$$(tput colors 2> /dev/null || echo 0)" -ge 8 ]; then printf "\033[34;1m▶\033[0m"; else printf "▶"; fi) | ||
|
||
GENERATED = # List of generated files | ||
|
||
GOIMPORTS = $(shell which goimports) | ||
GOCOV = $(shell which gocov) | ||
GOCOVXML=$(shell which gocov-xml) | ||
GOTESTSUM=$(shell which gotestsum) | ||
GOLANGCILINT=$(shell which golangci-lint) | ||
|
||
.SUFFIXES: | ||
.PHONY: all | ||
#all: fmt golangci-lint-run $(GENERATED) | $(basename $(MODULE)) ; $(info $(M) building executable…) @ ## Build program binary | ||
all: fmt golangci-lint-run $(GENERATED) | wombatt ; $(info $(M) building executable…) @ ## Build program binary | ||
|
||
.PHONY: wombatt | ||
wombatt: $(shell find -name \*.go) | ||
$Q CGO_ENABLED=0 GOOS=${GOOS} GOARCH=${GOARCH} $(GO) build \ | ||
-tags release \ | ||
-ldflags '-s -w -X $(MODULE)/cmd.Version=$(VERSION) -X $(MODULE)/cmd.BuildDate=$(DATE)' \ | ||
-o $(BINARY) main.go | ||
# Tools | ||
|
||
goimports: | ||
ifeq (, $(GOIMPORTS)) | ||
$(error "No goimport in $$PATH, please run 'make install-tools') | ||
endif | ||
|
||
gocov: | ||
ifeq (, $(GOCOV)) | ||
$(error "No gocov in $$PATH, please run 'make install-tools') | ||
endif | ||
|
||
gocov-xml: | ||
ifeq (, $(GOCOVXML)) | ||
$(error "No gocov-xml in $$PATH, please run 'make install-tools') | ||
endif | ||
|
||
gotestsum: | ||
ifeq (, $(GOTESTSUM)) | ||
$(error "No gotestsum in $$PATH, please run 'make install-tools') | ||
endif | ||
|
||
golangci-lint: | ||
ifeq (, $(GOLANGCILINT)) | ||
$(error "No golangci-lint $$PATH, please run 'make install-tools') | ||
endif | ||
|
||
install-tools: | ||
test -x "$(GOIMPORTS)" || go install golang.org/x/tools/cmd/goimports@latest | ||
test -x "$(GOCOV)" || go install github.com/axw/gocov/gocov@latest | ||
test -x "$(GOCOVXML)" || go install github.com/AlekSi/gocov-xml@latest | ||
test -x "$(GOTESTSUM)" || go install gotest.tools/gotestsum@latest | ||
test -x "$(GOLANGCILINT)" || go install github.com/golangci/golangci-lint/cmd/[email protected] | ||
|
||
# Generate | ||
|
||
# Tests | ||
|
||
TEST_TARGETS := test-short test-race | ||
.PHONY: $(TEST_TARGETS) check test tests | ||
test-short: ARGS=-short ## Run only short tests | ||
test-race: ARGS=-race ## Run tests with race detector | ||
$(TEST_TARGETS): NAME=$(MAKECMDGOALS:test-%=%) | ||
$(TEST_TARGETS): test | ||
check test tests: fmt golangci-lint-run $(GENERATED) | gotestsum ; $(info $(M) running $(NAME:%=% )tests…) @ ## Run tests | ||
$Q mkdir -p test | ||
$Q gotestsum --junitfile test/tests.xml -- -timeout $(TIMEOUT)s $(ARGS) $(PKGS) | ||
.PHONY: test-bench | ||
test-bench: $(GENERATED) ; $(info $(M) running benchmarks…) @ ## Run benchmarks | ||
$Q gotestsum -f standard-quiet -- --timeout $(TIMEOUT)s -run=__absolutelynothing__ -bench=. $(PKGS) | ||
|
||
COVERAGE_MODE = atomic | ||
.PHONY: test-coverage | ||
test-coverage: fmt golangci-lint-run $(GENERATED) | ||
test-coverage: | gocov gocov-xml gotestsum ; $(info $(M) running coverage tests…) @ ## Run coverage tests | ||
$Q mkdir -p test | ||
$Q gotestsum -- \ | ||
-coverpkg=$(shell echo $(PKGS) | tr ' ' ',') \ | ||
-covermode=$(COVERAGE_MODE) \ | ||
-coverprofile=test/profile.out $(PKGS) | ||
$Q $(GO) tool cover -html=test/profile.out -o test/coverage.html | ||
$Q gocov convert test/profile.out | gocov-xml > test/coverage.xml | ||
@echo -n "Code coverage: "; \ | ||
echo "scale=1;$$(sed -En 's/^<coverage line-rate="([0-9.]+)".*/\1/p' test/coverage.xml) * 100 / 1" | bc -q | ||
|
||
.PHONY: golangci-lint-run | ||
golangci-lint-run: | golangci-lint ; $(info $(M) running golangci-lint…) @ | ||
$Q golangci-lint run | ||
|
||
.PHONY: fmt | ||
fmt: | goimports ; $(info $(M) running gofmt…) @ ## Run gofmt on all source files | ||
$Q goimports -local $(MODULE) -w $(shell $(GO) list -f '{{$$d := .Dir}}{{range $$f := .GoFiles}}{{printf "%s/%s\n" $$d $$f}}{{end}}{{range $$f := .CgoFiles}}{{printf "%s/%s\n" $$d $$f}}{{end}}{{range $$f := .TestGoFiles}}{{printf "%s/%s\n" $$d $$f}}{{end}}' $(PKGS)) | ||
|
||
# Misc | ||
|
||
.PHONY: clean | ||
clean: ; $(info $(M) cleaning…) @ ## Cleanup everything | ||
@rm -rf $(PKG) test $(GENERATED) $(BINARY) | ||
|
||
.PHONY: help | ||
help: | ||
@grep -hE '^[ a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \ | ||
awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-17s\033[0m %s\n", $$1, $$2}' | ||
|
||
.PHONY: version | ||
version: | ||
@echo $(VERSION) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
NAME:=wombatt | ||
VERSION:=0.0.1 | ||
LINUX_ARCH:=amd64 arm arm64 | ||
|
||
all: | ||
@echo Use the 'release' target to build a release | ||
|
||
release: build tar | ||
|
||
.PHONY: build | ||
build: | ||
@go version | ||
@echo Cleaning old builds | ||
@rm -rf build && mkdir build | ||
@echo Building: darwin/amd64 - $(VERSION) | ||
mkdir -p build/darwin/amd64 && GOOS=darwin GOARCH=amd64 $(MAKE) $(NAME) BINARY=build/darwin/amd64/$(NAME) | ||
@echo Building: darwin/arm64 - $(VERSION) | ||
mkdir -p build/darwin/arm64 && GOOS=darwin GOARCH=arm64 $(MAKE) $(NAME) BINARY=build/darwin/arm64/$(NAME) | ||
@echo Building: windows/amd64 - $(VERSION) | ||
mkdir -p build/windows/amd64 && GOOS=windows GOARCH=amd64 $(MAKE) $(NAME) BINARY=build/windows/amd64/$(NAME).exe | ||
@echo Building: linux/$(LINUX_ARCH) - $(VERSION) ;\ | ||
for arch in $(LINUX_ARCH); do \ | ||
mkdir -p build/linux/$$arch && GOOS=linux GOARCH=$$arch $(MAKE) $(NAME) BINARY=build/linux/$$arch/$(NAME) ;\ | ||
done | ||
|
||
.PHONY: tar | ||
tar: | ||
@echo Cleaning old releases | ||
@rm -rf release && mkdir release | ||
tar -zcf release/$(NAME)_$(VERSION)_darwin_amd64.tgz -C build/darwin/amd64 $(NAME) | ||
tar -zcf release/$(NAME)_$(VERSION)_darwin_arm64.tgz -C build/darwin/arm64 $(NAME) | ||
tar -zcf release/$(NAME)_$(VERSION)_windows_amd64.tgz -C build/windows/amd64 $(NAME).exe | ||
for arch in $(LINUX_ARCH); do \ | ||
tar -zcf release/$(NAME)_$(VERSION)_linux_$$arch.tgz -C build/linux/$$arch $(NAME) ;\ | ||
done | ||
|
||
.PHONY: version | ||
version: | ||
@echo $(VERSION) | ||
|
||
.PHONY: clean | ||
clean: | ||
rm -rf release | ||
rm -rf build | ||
rm -f wombatt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
![wombatt logo](https://github.com/gonzalop/wombatt/blob/main/extras/wombatt-small.jpg?raw=true) | ||
# wombatt | ||
|
||
wombatt is a set of tools to monitor batteries and inverters, and to send commands to inverters. | ||
The initial version only supports EG4LLv2 batteries and any inverter using the PI30 protocol family. | ||
|
||
## Compilation from Source | ||
|
||
To compile wombatt, you need a working Go setup. Then check out the project and run `make` to compile the wombatt binary: | ||
|
||
~~~ | ||
$ git clone https://github.com/gonzalop/wombatt.git | ||
$ cd wombatt | ||
$ make | ||
~~~ | ||
|
||
And you'll get a `wombatt` binary. | ||
|
||
If you want to cross-compile for linux, windows, and Mac: | ||
|
||
~~~ | ||
$ git clone https://github.com/gonzalop/wombatt.git | ||
$ cd wombatt | ||
$ make -f Makefile.release release | ||
~~~ | ||
|
||
And you'll get the different binaries under `build/` and tarfiles under `releases/`. | ||
|
||
## Subcommands and usage | ||
Run `wombatt <subcommand> -h` for help on any specific command. | ||
|
||
### battery-info | ||
`battery-info` displays battery status information. | ||
|
||
For instance, to query the battery with ID #2: | ||
~~~ | ||
$ ./wombatt battery-info --serial-port /dev/ttyUSB0 --battery-ids 2 | ||
Battery #2 | ||
=========== | ||
battery voltage: 52.9V | ||
current: 2.5A | ||
cell 1 voltage: 3.305V | ||
cell 2 voltage: 3.306V | ||
cell 3 voltage: 3.306V | ||
cell 4 voltage: 3.306V | ||
cell 5 voltage: 3.306V | ||
cell 6 voltage: 3.307V | ||
cell 7 voltage: 3.306V | ||
cell 8 voltage: 3.307V | ||
cell 9 voltage: 3.306V | ||
cell 10 voltage: 3.307V | ||
cell 11 voltage: 3.306V | ||
cell 12 voltage: 3.306V | ||
cell 13 voltage: 3.306V | ||
cell 14 voltage: 3.307V | ||
cell 15 voltage: 3.306V | ||
cell 16 voltage: 3.307V | ||
pcb temp: 31°C | ||
max temp: 32°C | ||
avg temp: 30°C | ||
cap remaining: 46% | ||
max charging current: 100A | ||
soh: 100% | ||
soc: 47% | ||
status: inactive/charging | ||
warning: 0 | ||
protection: 0 | ||
error code: 0 | ||
cycle counts: 10 | ||
full capacity: 100000mAh | ||
temp1: 30°C | ||
temp2: 30°C | ||
temp3: 30°C | ||
temp4: 30°C | ||
temp5: 0 | ||
temp6: 0 | ||
cell num: 16 | ||
designed capacity: 100Ah | ||
cell balance status: 0 | ||
max cell voltage: 3.307V | ||
min cell voltage: 3.305V | ||
mean cell voltage: 3.306V | ||
median cell voltage: 3.306V | ||
model: LFP-51.2V100Ah-V1.0 | ||
firmware version: Z02T04 | ||
serial: 2022-10-26 | ||
~~~ | ||
|
||
If `battery-ids` is omitted, it will scan IDs from 1 to 64. | ||
|
||
### inverter-query | ||
`inverter-query` sends PI30 protocol commands to inverters. | ||
|
||
Below, an example of running a single command: | ||
~~~ | ||
$ ./wombatt inverter-query -p /dev/ttyS1 --commands Q1 | ||
2023/09/17 11:35:13.619499 [00001 00006 00 00 07 037 039 043 038 02 00 000 0036 0000 0000 60.00 11 0 060 030 120 030 58.40 000 120 0 0000] | ||
Device: /dev/ttyS1, Command: Q1 | ||
======================================== | ||
Time until the end of absorb charging: 1s | ||
Time until the end of float charging: 6s | ||
SCC flags: Not communicating | ||
SCC PWM temperature: 37°C | ||
Inverter temperature: 39°C | ||
Battery temperature: 43°C | ||
Transformer temperature: 38°C | ||
GPIO13: 2 | ||
Fan lock status: not locked | ||
Fan PWM speed: 36% | ||
SCC charge power: 0W | ||
Parallel warning: 0 | ||
Sync frequency: 60Hz | ||
Inverter charger status: bulk stage | ||
~~~ | ||
|
||
### monitor-inverters | ||
`monitor-inverters` monitors inverters using PI30 protocol, MQTT publishing optional. | ||
|
||
The command below will monitor the inverters connected to /dev/ttyS0 and | ||
/dev/ttyS1, run the `Q1`, `QPIGS`, and `QPIRI` commands on both of them, | ||
and `QPGS1` or `QPGS2`. | ||
|
||
~~~ | ||
$ ./wombatt monitor-inverters -w :9000 --mqtt-broker tcp://127.0.0.1:1883 --mqtt-user youruser --mqtt-password yourpassword /dev/ttyS0,Q1:QPIGS:QPIRI:QPGS2,eg4_1 /dev/ttyS1,Q1:QPIGS:QPIRI:QPGS1,eg4_2 | ||
~~~ | ||
|
||
The information will be published to the specified MQTT maserver with prefixes `eg4_1` | ||
and `eg4_2` depending on the inverter, along HomeAssistant autodiscovery configuration. | ||
|
||
The same infomation is made available via web on port 9000 | ||
(http://127.0.0.1:9000/inverters/1/Q1 and so on) as text or JSON (add | ||
`?format=json` to the URL), with the ability to request specific | ||
fields (`?fields=<name>`). | ||
|
||
### monitor-batteries | ||
`monitor-batteries` monitors batteries state, MQTT publishing optional. | ||
|
||
For instance, to monitor batteries with IDs 2 thru 6, and publish to MQTT and a local web page on port 8000, you can run: | ||
~~~ | ||
$ ./wombatt monitor-batteries -w :8000 -p /dev/ttyUSB1 --mqtt-broker tcp://127.0.0.1:1883 --mqtt-user youruser --mqtt-password yourpassword --battery-ids 2,3,4,5,6 | ||
~~~ | ||
|
||
The default prefix for the items added to MQTT is `eg4` (i.e., `homeassistant/eg4_battery2_info/...`). | ||
|
||
The same infomation is made available via web on port 8000 | ||
(http://127.0.0.1:9000/battery/2 and so on) as text or JSON (add | ||
`?format=json` to the URL), with the ability to request specific | ||
fields (`?fields=<name>`). | ||
|
||
### modbus-read | ||
`modbus-read` reads registers from a specified device. This is used during development. | ||
|
||
To read 38 registers from device ID #2 starting at address 0: | ||
~~~ | ||
$ ./wombatt modbus-read -p /dev/ttyUSB1 --id 2 --start 0 --count 38 | ||
/wombat modbus-read -p ~/dev/Batteries --id 2 --start 0 --count 38 | ||
/dev/ttyUSB1: | ||
00000000 02 03 4c 14 af 00 f0 0c ed 0c ee 0c ed 0c ef 0c |..L.............| | ||
00000010 ed 0c ee 0c ed 0c ee 0c ee 0c ef 0c ee 0c ee 0c |................| | ||
00000020 ed 0c ee 0c ed 0c ee 00 1f 00 20 00 1e 00 30 00 |.......... ...0.| | ||
00000030 64 00 64 00 30 00 01 00 00 00 00 00 00 00 00 00 |d.d.0...........| | ||
00000040 0a 15 75 2a 00 1e 1e 1e 1e 00 00 00 10 03 e8 45 |..u*...........E| | ||
00000050 8d |.| | ||
~~~ | ||
|
||
|
||
### forward | ||
`forward` read/writes between 2 ports, displaying the information exchanged in hexadecimal. This is used during development. | ||
|
||
~~~ | ||
$ ./wombatt forward --subordinate-port /dev/MasterBattery --controller-port ~/dev/Inverter | ||
2023/09/17 12:10:11.831759 Inverter: 8 010300130010b5c3 | ||
2023/09/17 12:10:11.875255 MasterBattery: 32 01032000660000003114ad05c8001e753072d8ea6002040000000a0000000015 | ||
2023/09/17 12:10:11.882400 MasterBattery: 5 e000004a8e | ||
~~~ | ||
|
||
## Reporting bugs and requesting features | ||
Please use https://github.com/gonzalop/wombatt/issues to report any bug, request new features | ||
or support for batteries, inverters, etc. | ||
|
Oops, something went wrong.