Metadata-Version: 2.1
Name: mate3
Version: 0.5.3
Summary: Outback Mate3s Python Library
Home-page: https://github.com/adamcharnock/mate3/
Author: Adam Charnock
Author-email: adam@adamcharnock.com
Requires-Python: >=3.7,<4.0
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Requires-Dist: fixedint (>=0.1.6,<0.2.0)
Requires-Dist: loguru (>=0.5.3,<0.6.0)
Requires-Dist: pymodbus (>=2.4,<3.0)
Project-URL: Repository, https://github.com/adamcharnock/mate3/
Description-Content-Type: text/markdown

# Outback Mate 3 & 3s Python library & command line interface

[![PyPI version](https://badge.fury.io/py/mate3.svg)](https://badge.fury.io/py/mate3)

This library provides complete support for all Outback devices (at least in theory, 
I don't own all the devices so cannot test it). Writing data is also supported.

This data is accessed though the Outback Mate3s' Modbus interface. You must therefore 
have a Mate3s which is connected to your local network using its ethernet port.

Tested on Python 3.7. May work on 3.6.

## Warnings

First, the big one:

> **WARNING!** Please make sure you read [the license](https://github.com/adamcharnock/mate3/blob/master/LICENSE) before using any of the `write` functionality. You could easily damage your equipment by setting incorrect values (directly or indirectly).

In addition, there are other edges cases that may cause problems, mostly related to if a device is re-assigned a new port. For example, you have two inverters, read some values, then switch their ports over in the Hub before writing some values - which may now go to the 'wrong' one. For now, it's safest not to do that, unless you restart the `Mate3Client` each time. On that note, the recommended approach if you need to poll over time is:

```python
while True:
    with Mate3Client(...) as client:
        client...
    sleep(1)
```

As opposed to

```python
with Mate3Client(...) as client:
    while True:
        client...
    sleep(1)
```

Why? It means you're getting point-in-time values, and don't have to worry about changes (such as ports being switched). There are exceptions, but you should know why you're doing it.

## Installation

The recommended installation is as follows:

```sh
pip install mate3
```

After this you should be able to run the `mate3` command.

## Using the library

More documentation is needed, but you can get a pretty code idea from [./examples/getting_started.py](./examples/getting_started.py), copied (somewhat) below. 

```python
with Mate3Client("192.168.1.12") as client:
        # Read all devices:
        client.read()
        
        # What's the system name?
        mate = client.devices.mate3
        print(mate.system_name)
        # >>> FieldValue[system_name] | Implemented | Read @ 2020-07-19 21:27:57.747231 | Value: --- | Clean
        
        # Get the battery voltage. Note that it's auto-scaled appropriately.
        fndc = client.devices.fndc
        print(fndc.battery_voltage)
        # >>> FieldValue[battery_voltage] | Implemented | Read @ 2020-07-19 21:27:57.795158 | Scale factor: -1 | Unscaled value: 544 | Value: 54.4 | Clean

        # Get the (raw) values for the same device type on different ports
        inverters = client.devices.fx_inverters
        for port in inverters:
            print(f"FET temp on port {port} = {inverters[port].fet_temperature.value}")
        # >>> FET temp on port 1 = 36
        # >>> FET temp on port 2 = 35

        # Read only battery voltage again and check only it's read time was updated (and not system name, as we didn't
        # read it)
        time.sleep(1)
        client.read(only=[fndc.battery_voltage])
        print(mate.system_name)
        # >>> FieldValue[system_name] ... 2020-07-19 21:27:57 ...
        print(fndc.battery_voltage)
        # >>> FieldValue[battery_voltage] ... 2020-07-19 21:27:58 ...
        
        # Nice. What about modbus fields that aren't implemented?
        print(mate.sched_1_ac_mode.implemented)
        # >>> False

        # Cool. Can we set a new value? Note that we don't need to worry about scaling etc.
        cc = client.devices.charge_controller.config
        volts = cc.absorb_volts
        print(volts)
        # >>> ... | Scale factor: -1 | Unscaled value: 535 | Value: 53.5 | Clean
        cc.absorb_volts.value = volts.value + 0.1
        print(volts)
        # >>> ... | Scale factor: -1 | Unscaled value: 535 | Value: 53.5 | Dirty (value to write: 536)
        
        # OK, but what about fun fields like Enums? It's doable ...
        new_value = cc.grid_tie_mode.field.options["Grid Tie Mode disabled"]
        cc.grid_tie_mode.value = new_value

        # Finally, write any values that have changed to the device itself - BE CAREFUL!
        client.write()
```

## Using the command line interface (CLI)

A simple CLI is available, with four main sub-commands:

- `read` - reads all of the values from the Mate3 and prints to stdout in a variety of formats.
- `write` - writes values to the Mate3. (If you're doing anything serious you should use the python API.)
- `devices` - shows the connected devices.
- `dump` - dumps all of the raw modbus values to a (JSON) file in a format compatible with `CachingModbusClient` which you can then share with others to help in debugging any problems you may have. 

For each you can access the help (i.e. `mate3 <cmd> -h`) for more information.

## Troubleshooting

Some ideas (which can be helpful for issues)

### Set log-level to DEBUG

See `mate3 -h` for the CLI, otherwise the following (or similar) for python code:

```python
from loguru import logger
logger.remove()
logger.add(sys.stderr, level="DEBUG")
```

### List the devices

```sh
$ mate3 devices --host ...
name                                               address    port
----                                               -------    ----
Mate3                                              40069      None
ChargeController                                   40986      4
ChargeControllerConfiguration                      41014      4
...
```
Are they all there?

### Create a dump of the raw modbus values

See `mate3 dump -h`. You can send the resulting JSON file to someone to help debug. (Just note that it includes all the data about the Mate, e.g. any passwords etc.)

## Writing data to Postgres

> NB: this used to be in `mate3_pg` command, but has been moved to `./examples/postgres_monitor.py`.

The `postgress_monitor.py` command reads data from your Mate3 and writes it to a Postgres database.

In addition to a Mate3s connected to your network, you will need:

* A running Postgres database
* A definitions YAML file. ([example](https://github.com/adamcharnock/mate3/blob/master/pg_config.yaml))

Example use:

```
$ python postgres_monitor.py \
    -H 192.168.0.123 \ 
    --definitions /path/to/my/definitions.yaml \
    --database-url postgres://username:password@host:5432/database_name \
    --debug
```

You will need to replace `192.168.0.123` with your Mate3s' IP. Replace `/path/to/my/pg_config.yaml` with 
a path to your definitions file (see [example](https://github.com/adamcharnock/mate3/blob/master/pg_config.yaml)).
Replace the `username`, `password`, `host`, and `database_name` values with those for your Postgres database.

Full details of the `postgres_monitor.py` command:

```
$ python postgres_monitor.py --help
usage: mate3_pg [-h] --host HOST [--port PORT] [--interval INTERVAL] [--database-url DATABASE_URL] --definitions DEFINITIONS [--hypertables] [--quiet] [--debug]

Read all available data from the Mate3 controller

optional arguments:
  -h, --help            show this help message and exit
  --host HOST, -H HOST  The host name or IP address of the Mate3
  --port PORT, -p PORT  The port number address of the Mate3
  --interval INTERVAL, -i INTERVAL
                        Polling interval in seconds
  --database-url DATABASE_URL
                        Postgres database URL
  --definitions DEFINITIONS
                        YAML definition file
  --hypertables         Should we create tables as hypertables? Use only if you are using TimescaleDB
  --quiet, -q           Hide status output. Only errors will be shown
  --debug               Show debug logging
```  

## Contributing

If you wish to edit the mate3 source (contributions are gladly received!), 
then you can get the project directly from GitHub:

```sh
# Install poetry if you don't have it already (if you're unsure, you don't have it)
pip install poetry

# Get the source
git clone https://github.com/adamcharnock/mate3.git
cd mate3

# Install mate3 and its dependencies. This also makes the mate3 command available.
poetry install

# Run the tests - there aren't many, so feel free to add more!
pytest .
```

After this you should be able to run the `mate3` command and edit the project's source code.

## Release process

```sh
# Check everything has been comitted
git diff

# Up the version
poetry version {major|minor|bug}

# Update setup.py et al
dephell deps convert

# Review the resulting changes
git diff

# Build
poetry publish --build

# Docker: build & push
docker build -t adamcharnock/mate3:{VERSION_HERE} .
docker push adamcharnock/mate3:{VERSION_HERE}

# Commit
git ci  -m "Version bump"
git push
git push --tags
```

## Credits

This was originally a heavily refactored version of
[basrijn's Outback_Mate3 library](https://github.com/basrijn/Outback_Mate3), though has largely been completely rewritten since. Thanks anyway basrijn!

