vedirect/vedirect/defs.py

350 lines
12 KiB
Python

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Protocol definitions including fields, enums, and types."""
import collections
import enum
import pint
_ureg = pint.UnitRegistry()
class State(enum.IntEnum):
"""State is the state of operation. Sent in the `CS` field."""
# Off
OFF = 0
# Low power
LOW_POWER = 1
# Fault
FAULT = 2
# Bulk
BULK = 3
# Absorption
ABSORPTION = 4
# Float
FLOAT = 5
# Storage
STORAGE = 6
# Equalize (manual)
EQUALIZE_MANUAL = 7
# Inverting
INVERTING = 9
# Power supply
POWER_SUPPLY = 11
# Starting-up
STARTING_UP = 245
# Repeated absorption
REPEATED_ABSORPTION = 246
# Auto equalize / Recondition
AUTO_EQUALIZE_RECONDITION = 247
# BatterySafe
BATTERYSAFE = 248
# External Control
EXTERNAL_CONTROL = 252
class MPPTMode(enum.IntEnum):
"""MPPTMode is the state of the tracker. Sent in the `MPPT` field."""
# Off
OFF = 0
# Voltage or current limited
LIMITED = 1
# MPPT Tracker active
ACTIVE = 2
class Err(enum.IntEnum):
"""Err is the error code of the device. Sent in the `ERR` field."""
# No error
NO_ERROR = 0
# Battery voltage too high
BATTERY_VOLTAGE_TOO_HIGH = 2
# Charger temperature too high
CHARGER_TEMPERATURE_TOO_HIGH = 17
# Charger over current
CHARGER_OVER_CURRENT = 18
# Charger current reversed
CHARGER_CURRENT_REVERSED = 19
# Bulk time limit exceeded
BULK_TIME_LIMIT_EXCEEDED = 20
# Current sensor issue (sensor bias/sensor broken)
CURRENT_SENSOR_ISSUE = 21
# Terminals overheated
TERMINALS_OVERHEATED = 26
# Input voltage too high (solar panel)
INPUT_VOLTAGE_TOO_HIGH_SOLAR_PANEL = 33
# Input current too high (solar panel)
INPUT_CURRENT_TOO_HIGH_SOLAR_PANEL = 34
# Input shutdown (due to excessive battery voltage)
INPUT_SHUTDOWN = 38
# Factory calibration data lost
FACTORY_CALIBRATION_DATA_LOST = 116
# Invalid/incompatible firmware
INVALID_OR_INCOMPATIBLE_FIRMWARE = 117
# User settings invalid
USER_SETTINGS_INVALID = 119
class Load(enum.IntEnum):
"""Load is the state of the output to the load.
Sent in the `LOAD` field."""
# Off
OFF = 0
# On
ON = 1
# Kinds maps the common units to the appropriate scale and unit.
_KINDS = {
'mV': 1e-3 * _ureg.volt,
'mA': 1e-3 * _ureg.amp,
'W': 1 * _ureg.watt,
'0.01 kWh': 1e-2 * 1000 * _ureg.watt * _ureg.hour,
'0.01 V': 1e-2 * _ureg.volt,
'0.1 A': 1e-1 * _ureg.amp,
'Seconds': _ureg.second,
'HSDS': 1 * _ureg.day,
'ERR': Err,
'CS': State,
'MPPT': MPPTMode,
'LOAD': Load,
'SER#': str,
'PID': str,
'FW': str,
}
class Field(collections.namedtuple('Field', 'label unit description')):
"""Field describes a single field."""
def kind(self):
return _KINDS.get(self.unit, _KINDS.get(self.label, None))
V = Field('V', 'mV', 'Main or channel 1 (battery) voltage')
V2 = Field('V2', 'mV', 'Channel 2 (battery) voltage')
V3 = Field('V3', 'mV', 'Channel 3 (battery) voltage')
VS = Field('VS', 'mV', 'Auxiliary (starter) voltage')
VM = Field('VM', 'mV', 'Mid-point voltage of the battery bank')
DM = Field('DM', '%', 'Mid-point deviation of the battery bank')
VPV = Field('VPV', 'mV', 'Panel voltage')
PPV = Field('PPV', 'W', 'Panel power')
I = Field('I', 'mA', 'Main or channel 1 battery current') # noqa: E741
I2 = Field('I2', 'mA', 'Channel 2 battery current')
I3 = Field('I3', 'mA', 'Channel 3 battery current')
IL = Field('IL', 'mA', 'Load current')
LOAD = Field('LOAD', '', 'Load output state (ON/OFF)')
T = Field('T', '°C', 'Battery temperature')
P = Field('P', 'W', 'Instantaneous power')
CE = Field('CE', 'mAh', 'Consumed Amp Hours')
SOC = Field('SOC', '%', 'State-of-charge')
TTG = Field('TTG', 'Minutes', 'Time-to-go')
Alarm = Field('Alarm', '', 'Alarm condition active')
Relay = Field('Relay', '', 'Relay state')
AR = Field('AR', '', 'Alarm reason')
OR = Field('OR', '', 'Off reason')
H1 = Field('H1', 'mAh', 'Depth of the deepest discharge')
H2 = Field('H2', 'mAh', 'Depth of the last discharge')
H3 = Field('H3', 'mAh', 'Depth of the average discharge')
H4 = Field('H4', '', 'Number of charge cycles')
H5 = Field('H5', '', 'Number of full discharges')
H6 = Field('H6', 'mAh', 'Cumulative Amp Hours drawn')
H7 = Field('H7', 'mV', 'Minimum main (battery) voltage')
H8 = Field('H8', 'mV', 'Maximum main (battery) voltage')
H9 = Field('H9', 'Seconds', 'Number of seconds since last full charge')
H10 = Field('H10', '', 'Number of automatic synchronizations')
H11 = Field('H11', '', 'Number of low main voltage alarms')
H12 = Field('H12', '', 'Number of high main voltage alarms')
H13 = Field('H13', '', 'Number of low auxiliary voltage alarms')
H14 = Field('H14', '', 'Number of high auxiliary voltage alarms')
H15 = Field('H15', 'mV', 'Minimum auxiliary (battery) voltage')
H16 = Field('H16', 'mV', 'Maximum auxiliary (battery) voltage')
H17 = Field('H17', '0.01 kWh', 'Amount of discharged energy')
H18 = Field('H18', '0.01 kWh', 'Amount of charged energy')
H19 = Field('H19', '0.01 kWh', 'Yield total (user resettable counter)')
H20 = Field('H20', '0.01 kWh', 'Yield today')
H21 = Field('H21', 'W', 'Maximum power today')
H22 = Field('H22', '0.01 kWh', 'Yield yesterday')
H23 = Field('H23', 'W', 'Maximum power yesterday')
ERR = Field('ERR', '', 'Error code')
CS = Field('CS', '', 'State of operation')
BMV = Field('BMV', '', 'Model description (deprecated)')
FW = Field('FW', '', 'Firmware version (16 bit)')
FWE = Field('FWE', '', 'Firmware version (24 bit)')
PID = Field('PID', '', 'Product ID')
SER = Field('SER#', '', 'Serial number')
HSDS = Field('HSDS', '', 'Day sequence number (0..364)')
MODE = Field('MODE', '', 'Device mode')
AC_OUT_V = Field('AC_OUT_V', '0.01 V', 'AC output voltage')
AC_OUT_I = Field('AC_OUT_I', '0.1 A', 'AC output current')
AC_OUT_S = Field('AC_OUT_S', 'VA', 'AC output apparent power')
WARN = Field('WARN', '', 'Warning reason')
MPPT = Field('MPPT', '', 'Tracker operation mode')
FIELDS = (
# These fields have been tested.
PID,
FW,
SER,
V,
I,
VPV,
PPV,
CS,
MPPT,
ERR,
LOAD,
IL,
H19,
H20,
H21,
H22,
H23,
HSDS,
)
FIELD_MAP = {x.label: x for x in FIELDS}
PIDS = {
0x203: 'BMV-700',
0x204: 'BMV-702',
0x205: 'BMV-700H',
0x0300: 'BlueSolar MPPT 70|15',
0xA040: 'BlueSolar MPPT 75|50',
0xA041: 'BlueSolar MPPT 150|35',
0xA042: 'BlueSolar MPPT 75|15',
0xA043: 'BlueSolar MPPT 100|15',
0xA044: 'BlueSolar MPPT 100|30',
0xA045: 'BlueSolar MPPT 100|50',
0xA046: 'BlueSolar MPPT 150|70',
0xA047: 'BlueSolar MPPT 150|100',
0xA049: 'BlueSolar MPPT 100|50 rev2',
0xA04A: 'BlueSolar MPPT 100|30 rev2',
0xA04B: 'BlueSolar MPPT 150|35 rev2',
0xA04C: 'BlueSolar MPPT 75|10',
0xA04D: 'BlueSolar MPPT 150|45',
0xA04E: 'BlueSolar MPPT 150|60',
0xA04F: 'BlueSolar MPPT 150|85',
0xA050: 'SmartSolar MPPT 250|100',
0xA051: 'SmartSolar MPPT 150|100',
0xA052: 'SmartSolar MPPT 150|85',
0xA053: 'SmartSolar MPPT 75|15',
0xA054: 'SmartSolar MPPT 75|10',
0xA055: 'SmartSolar MPPT 100|15',
0xA056: 'SmartSolar MPPT 100|30',
0xA057: 'SmartSolar MPPT 100|50',
0xA058: 'SmartSolar MPPT 150|35',
0xA059: 'SmartSolar MPPT 150|100 rev2',
0xA05A: 'SmartSolar MPPT 150|85 rev2',
0xA05B: 'SmartSolar MPPT 250|70',
0xA05C: 'SmartSolar MPPT 250|85',
0xA05D: 'SmartSolar MPPT 250|60',
0xA05E: 'SmartSolar MPPT 250|45',
0xA05F: 'SmartSolar MPPT 100|20',
0xA060: 'SmartSolar MPPT 100|20 48V',
0xA061: 'SmartSolar MPPT 150|45',
0xA062: 'SmartSolar MPPT 150|60',
0xA063: 'SmartSolar MPPT 150|70',
0xA064: 'SmartSolar MPPT 250|85 rev2',
0xA065: 'SmartSolar MPPT 250|100 rev2',
0xA066: 'BlueSolar MPPT 100|20',
0xA067: 'BlueSolar MPPT 100|20 48V',
0xA068: 'SmartSolar MPPT 250|60 rev2',
0xA069: 'SmartSolar MPPT 250|70 rev2',
0xA06A: 'SmartSolar MPPT 150|45 rev2',
0xA06B: 'SmartSolar MPPT 150|60 rev2',
0xA06C: 'SmartSolar MPPT 150|70 rev2',
0xA06D: 'SmartSolar MPPT 150|85 rev3',
0xA06E: 'SmartSolar MPPT 150|100 rev3',
0xA06F: 'BlueSolar MPPT 150|45 rev2',
0xA070: 'BlueSolar MPPT 150|60 rev2',
0xA071: 'BlueSolar MPPT 150|70 rev2',
0xA102: 'SmartSolar MPPT VE.Can 150/70',
0xA103: 'SmartSolar MPPT VE.Can 150/45',
0xA104: 'SmartSolar MPPT VE.Can 150/60',
0xA105: 'SmartSolar MPPT VE.Can 150/85',
0xA106: 'SmartSolar MPPT VE.Can 150/100',
0xA107: 'SmartSolar MPPT VE.Can 250/45',
0xA108: 'SmartSolar MPPT VE.Can 250/60',
0xA109: 'SmartSolar MPPT VE.Can 250/70',
0xA10A: 'SmartSolar MPPT VE.Can 250/85',
0xA10B: 'SmartSolar MPPT VE.Can 250/100',
0xA10C: 'SmartSolar MPPT VE.Can 150/70 rev2',
0xA10D: 'SmartSolar MPPT VE.Can 150/85 rev2',
0xA10E: 'SmartSolar MPPT VE.Can 150/100 rev2',
0xA10F: 'BlueSolar MPPT VE.Can 150/100',
0xA112: 'BlueSolar MPPT VE.Can 250/70',
0xA113: 'BlueSolar MPPT VE.Can 250/100',
0xA114: 'SmartSolar MPPT VE.Can 250/70 rev2',
0xA115: 'SmartSolar MPPT VE.Can 250/100 rev2',
0xA116: 'SmartSolar MPPT VE.Can 250/85 rev2',
0xA201: 'Phoenix Inverter 12V 250VA 230V',
0xA202: 'Phoenix Inverter 24V 250VA 230V',
0xA204: 'Phoenix Inverter 48V 250VA 230V',
0xA211: 'Phoenix Inverter 12V 375VA 230V',
0xA212: 'Phoenix Inverter 24V 375VA 230V',
0xA214: 'Phoenix Inverter 48V 375VA 230V',
0xA221: 'Phoenix Inverter 12V 500VA 230V',
0xA222: 'Phoenix Inverter 24V 500VA 230V',
0xA224: 'Phoenix Inverter 48V 500VA 230V',
0xA231: 'Phoenix Inverter 12V 250VA 230V',
0xA232: 'Phoenix Inverter 24V 250VA 230V',
0xA234: 'Phoenix Inverter 48V 250VA 230V',
0xA239: 'Phoenix Inverter 12V 250VA 120V',
0xA23A: 'Phoenix Inverter 24V 250VA 120V',
0xA23C: 'Phoenix Inverter 48V 250VA 120V',
0xA241: 'Phoenix Inverter 12V 375VA 230V',
0xA242: 'Phoenix Inverter 24V 375VA 230V',
0xA244: 'Phoenix Inverter 48V 375VA 230V',
0xA249: 'Phoenix Inverter 12V 375VA 120V',
0xA24A: 'Phoenix Inverter 24V 375VA 120V',
0xA24C: 'Phoenix Inverter 48V 375VA 120V',
0xA251: 'Phoenix Inverter 12V 500VA 230V',
0xA252: 'Phoenix Inverter 24V 500VA 230V',
0xA254: 'Phoenix Inverter 48V 500VA 230V',
0xA259: 'Phoenix Inverter 12V 500VA 120V',
0xA25A: 'Phoenix Inverter 24V 500VA 120V',
0xA25C: 'Phoenix Inverter 48V 500VA 120V',
0xA261: 'Phoenix Inverter 12V 800VA 230V',
0xA262: 'Phoenix Inverter 24V 800VA 230V',
0xA264: 'Phoenix Inverter 48V 800VA 230V',
0xA269: 'Phoenix Inverter 12V 800VA 120V',
0xA26A: 'Phoenix Inverter 24V 800VA 120V',
0xA26C: 'Phoenix Inverter 48V 800VA 120V',
0xA271: 'Phoenix Inverter 12V 1200VA 230V',
0xA272: 'Phoenix Inverter 24V 1200VA 230V',
0xA274: 'Phoenix Inverter 48V 1200VA 230V',
0xA279: 'Phoenix Inverter 12V 1200VA 120V',
0xA27A: 'Phoenix Inverter 24V 1200VA 120V',
0xA27C: 'Phoenix Inverter 48V 1200VA 120V',
0xA281: 'Phoenix Inverter 12V 1600VA 230V',
0xA282: 'Phoenix Inverter 24V 1600VA 230V',
0xA284: 'Phoenix Inverter 48V 1600VA 230V',
0xA291: 'Phoenix Inverter 12V 2000VA 230V',
0xA292: 'Phoenix Inverter 24V 2000VA 230V',
0xA294: 'Phoenix Inverter 48V 2000VA 230V',
0xA2A1: 'Phoenix Inverter 12V 3000VA 230V',
0xA2A2: 'Phoenix Inverter 24V 3000VA 230V',
0xA2A4: 'Phoenix Inverter 48V 3000VA 230V',
0xA340: 'Phoenix Smart IP43 Charger 12|50 (1+1)',
0xA341: 'Phoenix Smart IP43 Charger 12|50 (3)',
0xA342: 'Phoenix Smart IP43 Charger 24|25 (1+1)',
0xA343: 'Phoenix Smart IP43 Charger 24|25 (3)',
0xA344: 'Phoenix Smart IP43 Charger 12|30 (1+1)',
0xA345: 'Phoenix Smart IP43 Charger 12|30 (3)',
0xA346: 'Phoenix Smart IP43 Charger 24|16 (1+1)',
0xA347: 'Phoenix Smart IP43 Charger 24|16 (3)',
}