Skip to content

Commit

Permalink
Merge branch 'pr/16'
Browse files Browse the repository at this point in the history
  • Loading branch information
martinkong0806 committed Feb 2, 2022
2 parents 1f94dc9 + a6bdf19 commit 7234e7a
Show file tree
Hide file tree
Showing 22 changed files with 1,028 additions and 1,340 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
src/settings.py
5 changes: 3 additions & 2 deletions src/.gitignore → .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#Ignore settings file
settings.py
settings.old
__pycache__
read_debug.log
givtcp_debug.log
.venv
.vscode
5 changes: 1 addition & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ ENV MQTT_PASSWORD=""
ENV MQTT_TOPIC=""
ENV MQTT_PORT="1883"
ENV JSON_OUTPUT="False"
ENV DEBUG="False"
ENV LOG_LEVEL="Error"
ENV DEBUG_FILE_LOCATION=""
ENV PRINT_RAW="False"
ENV SELF_RUN="True"
Expand All @@ -34,9 +34,6 @@ ENV INFLUX_URL=""
ENV INFLUX_TOKEN=""
ENV INFLUX_BUCKET=""
ENV INFLUX_ORG=""
ENV HA_OUTPUT="False"
ENV HA_URL=""
ENV HA_TOKEN=""

EXPOSE 6345 1883

Expand Down
129 changes: 57 additions & 72 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,40 @@ A settings.py file is required in the root directory. Use the supplied settings_
# Execution of GivTCP
GivTCP can be executed in a number of ways and can be set to output data in multiple formats. Exact usage is dependent on your use-case and needs:

| Method | Description |
| ---------------| ------------------------------- |
| [CLI](#cli-usage) | Execute the script at the command line and pass the relevant function and parameters as per the details below |
| [CLI through Node-Read](#cli-through-node-red) | Using the Exec node in Node-Red to call the script in the same way as above. This allows automation of script calling within a wider automated system |
| [REST Service](#restful-service) | Deployed inside a Docker container a RESTful service calls the relevant functions using the details below through GET and POST http methods |
| [Docker container](#docker) | A docker container is available which has all code and pre-requisites installed and out of the box is set to auto-discover the invertor and publish to an internal MQTT broker. This can be changed to publish to an external broker by modifying the container ENV variables |
Reccomended usage is through the Docker container found here: https://hub.docker.com/repository/docker/britkat/giv_tcp-ma
This will set up a self-running service which will publish data as required and provide a REST interface for control. An internal MQTT broker can be activiated to make data avalable on the network.


# Output formats:
## MQTT
The script will publish directly to the nominated MQTT broker all the requested read data.

![image](https://user-images.githubusercontent.com/69121158/122302074-847e9980-cef9-11eb-87eb-f4010b0874ed.png)
<img width="245" alt="image" src="https://user-images.githubusercontent.com/69121158/149670766-0d9a6c92-8ee2-44d6-9045-2d21b6db7ebf.png">

## JSON
The functions return a JSON formated object which can then be consumed by other systems or functions, default output is to stdout

## InfluxDB
Publish Power and energy stats to your InfluxDB database using credentials you provide.

# GivTCP functions
## Read functions
GivTCP is able to retrieve key information from the GivEnergy Invertors through predefined functions:

### Available read functions are:
| Function | Payload | Description |
| ----------------- | ------------- | -------------------------------- |
| getTimeslots | None | Gets all currently stored timeslots for Charge1, Discharge1 and Discharge2 |
| getCombinedStats | None | Gets power and Energy Stats (real-time, Today and Total) |
| getModesandTimes | None | Gets the Timeslots and control state info including: Mode, Target Charge SOC, Battery Reserve, Charge and Discharge Schedule state (Paused/Active) and Battery Capacity |
| runAll | None | Runs all of the above |
GivTCP collects all invertor ad battery data through the "runAll" function. It creates a nested data structure with all data available in a structured format.
Data Elements are:
* Energy - Today and all-time Total
* Today
* Total
* Power - Real-time stats and power flow data
* Power stats (eg. Import)
* Power Flow (eg. Grid to House)
* Invertor Details - Status details such as Serial Number
* Timeslots - Charge and Discharge
* Control - Charge/Discharge rates, Battery SOC
* Battery Details - Status and real-time cell voltages
* Battery 1
* Battery 2
* ...


## Control functions
Expand All @@ -65,97 +72,53 @@ Control is available through predefined functions. The format of the function ca
|setBatteryMode|{"mode":"1"}| Sets battery operation mode. Mode value must be in the range 1-4|
|setDateTime|{"dateTime":"dd/mm/yyyy hh:mm:ss"}| Sets invertor time, format must be as shown here|

# CLI Usage
GivTCP can be called from any machine running Python3. The relevant script must be called and a function name passed to it as an argument. Exmaples of how to call read and write functions are shown here:

## Read
`python3 read.py {{functionName}}`

The full call to get all information by running the runAll function would then be:

`python3 read.py runAll`

## Control
`python3 write.py {{functionName}} '{{controlPayload}}'`

An example payload can be found below and further details can be seen in the GivEnergy Docs to be found here: XXXXXXX
Note: In order to send json payloads via CLI you will need to place the JSON string inside single quotes

The full call to set Charge Timeslot 1 would then be:

`python3 write.py setChargeSlot1 '{"enable": true,"start": "0100","finish": "0400","chargeToPercent": "100"}'`

# CLI through Node-Red

Node-Red provides the ability to call the python scripts through an "Exec" node. This essentially makes a command line call to the host OS, and mimics the CLI process above. The advantage of this execution method is that it allows integration into wider automation systems and provides a stable, self-healing ability to run the script on demand. wrapping this core code in a logic flow.

![image](https://user-images.githubusercontent.com/69121158/122303286-3bc7e000-cefb-11eb-93c5-bf48907bd189.png)

To execute this you must download the src files for this project, place them in an accessible folder on your machine running Node-Red then set the paramters of the Exec functon to call it.

Example Node-Red flows are vailable here: XXXX

# RESTful Service
GivTCP provides a wrapper function REST.py which uses Flask to expose the read and control functions as RESTful http calls. To utilise this service you will need to either use a WSGI serivce such as gunicorn or use the pre-built Docker container

## Gunicorn
Ensure Gunicorn is installed by running:

`pip install gunicorn`

Then call the service by initiating the following command from the same directory as the downloaded src files:

`gunicorn -w 4 -b 127.0.0.1:6345 REST:giv_api`

(where the 127.0.0.1:6345 is the IP address and port you want to bind the service to)

## Docker
# Docker
The docker container can be downloaded at the Docker hub here:
https://hub.docker.com/repository/docker/britkat/giv_tcp-ma

* Docker image is multi-architecture so docker should grab the correct version for your system (tested on x86 and rpi3)
* Create a container with the relevant ENV variables below (mimicing the settings.py file)
* Set the container to auto-restart to ensure reliability
* Out of the box the default setup enables local MQTT broker and REST service
* Out of the box the default setup enables local MQTT broker and REST service (see below for details)
* For Invertor autodiscovery to function your container must run on the "Host" network within docker (not Bridge). If it fails then you will need to manually add in INVERTOR_IP to the env variables

| ENV Name | Example | Description |
| ----------------------- | ------------- | -------------------------------- |
| INVERTOR_IP |192.168.10.1 | Docker container can auto detect Invertors if running on your host network. If this fails then add the IP manually to this ENV |
| NUMBATTERIES | 1 | Number of battery units connected to the invertor |
| MQTT_OUTPUT | True | Optional if set to True then MQTT_ADDRESS is required |
| MQTT_ADDRESS | 127.0.0.1 | Optional (but required if OUTPUT is set to MQTT) |
| MQTT_USERNAME | bob | Optional |
| MQTT_PASSWORD | cat | Optional |
| MQTT_TOPIC | GivEnergy/Data | Optional - default is Givenergy.<serial number>|
| DEBUG | False | Optional - if True then will write debug info to sepcified file location (default is same directory as the py files) |
| LOG_LEVEL | Error | Optional - you can choose Error, Info or Debug. Output will be sent to the debug file location if specified, otherwise it is sent to stdout|
| DEBUG_FILE_LOCATION | /usr/pi/data | Optional |
| PRINT_RAW | False | Optional - If set to True the raw register values will be returned alongside the normal data |
| INFLUX_OUTPUT | False | Optional - Used to enable publishing of energy and power data to influx |
| INFLUX_TOKEN |abcdefg123456789| Optional - If using influx this is the token generated from within influxdb itself |
| INFLUX_BUCKET |giv_bucket| Optional - If using influx this is data bucket to use|
| INFLUX_ORG |giv_tcp| Optional - If using influx this is the org that the token is assigned to |
| HA_OUTPUT | False |Optional - Used to enable publishing of energy and power data to Home Assistant |
| HA_URL |https://homeassistant.local:8123| URL of Home Assistant instance (noting correct use of IP or domain name, whichever works in your browser)|
| HA_TOKEN |abcdefg123456789| Optional - If using Home Assistant this is the Long Lasting Token generated from within Home Assistant itself |
| INFLUX_ORG |giv_tcp| Optional - If using influx this is the org that the token is assigned to |

# RESTful Service
GivTCP provides a wrapper function REST.py which uses Flask to expose the read and control functions as RESTful http calls. To utilise this service you will need to either use a WSGI serivce such as gunicorn or use the pre-built Docker container.

This can be used within a Node-Red flow to integrate into your automation or using Home Assistany REST sensors unsing the Home Assistant yaml package provided.
NB.This does require the Docker container running on your network.

### Calling RESTFul Functions
## Calling RESTFul Functions

The following table outlines the http methods needed to call the various read and control functions. For each control function the payload is an identical JSON string as above (minus the single quotes).
The RESTful Service will return a JSON object which you can then parse as you so desire

URL's below are based off the root http address of http://IP:6345
(Port may change if you are running yourself using gunicorn, in which case use the details specified in the gunicorn command)

#### Read Functions
### Read Functions
| URL | Method | payload |
| ------------------ | ------------ | -------------------- |
| /runAll| GET | None | |
| /getTimeslots| GET | None | |
| /getCombinedStats| GET | None | |
| /getModesandTimes| GET | None | |

#### Control Functions
### Control Functions
| URL | Method | payload |
| ------------------ | ------------ | -------------------- |
| /disableChargeTarget| POST | None |
Expand All @@ -172,3 +135,25 @@ URL's below are based off the root http address of http://IP:6345
| /setDischargeSlot2| POST | {"start":"0100","finish":"0400","dischargeToPercent":"55"} |
| /setBatteryMode| POST | {"mode":"1"} |
| /setDateTime|POST | {"dateTime":"dd/mm/yyyy hh:mm:ss"}|


## Gunicorn
If you don't wish to run the docker container, you can set up your own wysg application using Gunicorn/Flask.
Ensure Gunicorn is installed by running:

`pip install gunicorn`

Then call the service by initiating the following command from the same directory as the downloaded src files:

`gunicorn -w 4 -b 127.0.0.1:6345 REST:giv_api`

(where the 127.0.0.1:6345 is the IP address and port you want to bind the service to)

# CLI Usage
GivTCP can be called from any machine running Python3. The relevant script must be called and a function name passed to it as an argument.

An example payload can be found below.
Note: In order to send json payloads via CLI you will need to place the JSON string inside single quotes

The full call to set Charge Timeslot 1 would then be:
`python3 write.py setChargeSlot1 '{"enable": true,"start": "0100","finish": "0400","chargeToPercent": "100"}'`
3 changes: 1 addition & 2 deletions buildx.bat
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
git pull
docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 -t britkat/giv_tcp-ma:2021.11.24 --push .
docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 -t britkat/giv_tcp-ma:refactor --push .
42 changes: 0 additions & 42 deletions documentaion/APIDocumentation.md

This file was deleted.

Binary file removed documentaion/registersAndFunctions.xlsb.xlsx
Binary file not shown.
32 changes: 0 additions & 32 deletions documentaion/tutorial.md

This file was deleted.

Loading

0 comments on commit 7234e7a

Please sign in to comment.