Python library & CLI for your Outback/Mate3s solar power system
MIT License
This Python library aims to provide complete support for all Outback devices connected to a Mate3/Mate3s (or AXS port?) via Modbus. You can:
Tested on Python 3.7. May work on 3.6.
The recommended installation is as follows:
pip install mate3
After this you should be able to run the mate3
command. To access your Mate it must be connected to your local network using its ethernet port.
Reading this will help you understand this libary and how to interact with your Mate.
Hopefully, you don't need to worry about Modbus at all - this library should abstract that away for you. The key thing to note is that Modbus is a communication protocol, and this library works by interacting with the Mate3 physical devices using synchronous messages. So:
read
or write
before/after any operation you make.read
s or write
s you might brick the Modbus interface of your Mate (requiring a reboot to fix). As a rule of thumb, you probably don't want to be reading more frequently than once per second (and even then, preferably only specific fields, and not the whole lot). Since it's a communication protocol (and it's not actually clear what the latency is inherent in the Mate), there's not much point reading faster that this anyway.Mate3Client
, which can allow you to completely avoid interacting with/bricking your Mate while you're developing code etc. It's really tedious having to restart it every time your have a bug in your code.-1
is appearing as 65535
then yeh, that may be it.You can check out the details of how Outback implements Modbus in ./mate3/sunspec/doc, but the key things to note are:
charge_controller.config.absorb_volts
. Here the charge_controller
is the SunSpec block, and we add on a special config
field which is actually a pointer to the Outback configuration block. This is to try to abstract away the implementation details so you don't have to worry about their being multiple charge controller things, etc.Words are confusing. For now, take the below as a rough guide:
Field
- this is a definition of a field e.g. absorb_volts
is Uint16
with units of "Volts"
etc.Model
- This is generally referring to a specific Modbus 'block' - which is really just a collection of fields that are generally aligned to a specific device e.g. an inverter model will have an output KWH field, which a charge controller model won't. (Again, it's confusing here as Outback generally have two models per device.) In the case above charge_controller
represents one (SunSpec) model, and charge_controller.config
another (Outback) model.Device
- this is meant to represent a physical device and is basically our way of wrapping the Outback config model with the SunSpec one.FieldValue
- this is kind of like a Field
but with data (read from Modbus) included i.e. "the value of the field". It includes some nice things too like auto-scaling variables ('cos floats aren't a thing) and simple read
or write
APIs.At this stage, it doesn't exist - the best documentation is the code and the examples, though this only works well for those who know Python. A few other quick tips:
More documentation is needed (see above), but you can get a pretty code idea from ./examples/getting_started.py, copied (somewhat) below.
# Creating a client allows you to interface with the Mate. It also does a read of all devices connected to it (via the
# hub) on initialisation:
with Mate3Client("...") as client:
# What's the system name?
mate = client.devices.mate3
print(mate.system_name)
# >>> FieldValue[system_name] | Mode.RW | Implemented | Value: OutBack Power Technologies | Read @ 2021-01-01 17:50:54.373077
# Get the battery voltage. Note that it's auto-scaled appropriately.
fndc = client.devices.fndc
print(fndc.battery_voltage)
# >>> FieldValue[battery_voltage] | Mode.R | Implemented | Scale factor: -1 | Unscaled value: 506 | Value: 50.6 | ...
Read @ 2021-01-01 17:50:54.378941
# Get the (raw) values for the same device type on different ports.
inverters = client.devices.single_phase_radian_inverters
for port, inverter in inverters.items():
print(f"Output KW for inverter on port {port} is {inverter.output_kw.value}")
# >>> Output KW for inverter on port 1 is 0.7
# >>> Output KW for inverter on port 2 is 0.0
# Values aren't 'live' - they're only updated whenever you initialise the client, call client.update_all() or
# re-read a particular value. Here's how we re-read the battery voltage. Note the change in the last_read field
time.sleep(0.1)
fndc.battery_voltage.read()
print(fndc.battery_voltage)
# >>> FieldValue[battery_voltage] | Mode.R | Implemented | Scale factor: -1 | Unscaled value: 506 | Value: 50.6 | Read @ 2021-01-01 17:50:54.483401
# Nice. Modbus fields that aren't implemented are easy to identify:
print(mate.alarm_email_enable.implemented)
# >>> False
# We can write new values to the device too. Note that we don't need to worry about scaling etc.
# WARNING: this will actually write stuff to your mate - see the warning below!
mate.system_name.write("New system name")
print(mate.system_name)
# >>> FieldValue[system_name] | Mode.RW | Implemented | Value: New system name | Read @ 2021-01-01 17:50:54.483986
# All the fields and options are well defined so e.g. for enums you can see valid options e.g:
print(list(mate.ags_generator_type.field.options))
# >>> [<ags_generator_type.AC Gen: 0>, <ags_generator_type.DC Gen: 1>, <ags_generator_type.No Gen: 2>]
# In this case these are normal python Enums, so you can access them as expected, and assign them:
mate.ags_generator_type.write(mate.ags_generator_type.field.options["DC Gen"])
# >>> ags_generator_type.DC Gen
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.
First, the big one:
WARNING! Please make sure you read the 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 to recreate the Mate3Client
on every poll (as opposed to re-using one), as that'll help avoid these (or other) issues. There are exceptions to this rule, but you should know why you're breaking it before you do so.
Some ideas (which can be helpful for issues)
See mate3 -h
for the CLI, otherwise the following (or similar) for python code:
from loguru import logger
logger.remove()
logger.add(sys.stderr, level="DEBUG")
$ mate3 devices --host ...
name address port
---- ------- ----
Mate3 40069 None
ChargeController 40986 4
ChargeControllerConfiguration 41014 4
...
Are they all there?
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.)
See ./examples/postgres_monitor/README.md
This was originally a heavily refactored version of basrijn's Outback_Mate3 library, though has largely been completely rewritten since. Thanks anyway basrijn!