def buy_power(self): """ AC_INPUT -> BATTERIES + AC_OUTPUT """ if self.buy_current is not None and self.input_voltage is not None: return Value( (float(self.buy_current) * float(self.input_voltage)) / 1000.0, units='kW', resolution=2) return None
def chg_power(self): """ AC_INPUT -> BATTERIES Power consumed by the inverter from the AC input to charge the battery bank """ if self.chg_current is not None and self.input_voltage is not None: return Value( (float(self.chg_current) * float(self.input_voltage)) / 1000.0, units='kW', resolution=2) return None
def sell_power(self): """ BATTERIES -> AC_INPUT Power produced by the inverter from the batteries, sold back to the grid (AC input) """ if self.sell_current is not None and self.output_voltage is not None: return Value( (float(self.sell_current) * float(self.output_voltage)) / 1000.0, units='kW', resolution=2) return None
def inv_power(self): """ BATTERIES -> AC_OUTPUT Power produced by the inverter from the battery """ if self.inverter_current is not None and self.output_voltage is not None: return Value( (float(self.inverter_current) * float(self.output_voltage)) / 1000.0, units='kW', resolution=2) return None
def from_buffer(cls, data): values = cls.fmt.unpack(data) status = MXStatusPacket() # The following was determined by poking values at the MATE unit... raw_ah = ((values[0] & 0x70) >> 4) | values[ 4] # Ignore bit7 (if 0, MATE hides the AH reading) bat_current_milli = (values[0] & 0x0F) / 10.0 status.amp_hours = Value(raw_ah, units='Ah', resolution=0) status.pv_current = Value((128 + values[1]) % 256, units='A', resolution=0) status.bat_current = Value( ((128 + values[2]) % 256 + bat_current_milli), units='A', resolution=1) raw_kwh = (values[3] << 8) | values[8] status.kilowatt_hours = Value(raw_kwh / 10.0, units='kWh', resolution=1) status.aux_state = ((values[5] & 0x40) == 0x40) # 0: Off, 1: On status.aux_mode = (values[5] & 0x3F) status.status = values[6] status.errors = values[7] status.bat_voltage = Value(values[9] / 10.0, units='V', resolution=1) status.pv_voltage = Value(values[10] / 10.0, units='V', resolution=1) # Also add the raw packet, in case any of the above changes status.raw = data return status
def from_buffer(cls, data): values = cls.fmt.unpack(data) # Need this to determine whether the system is 230v or 110v misc = values[10] status = FXStatusPacket(misc) # When misc:0 == 1, you must multiply voltages by 2, and divide currents by 2 if status.is_230v: vmul = 2.0 imul = 0.5 else: vmul = 1.0 imul = 1.0 # From MATE2 doc the status packet contains: # Inverter address # Inverter current - AC current the FX is delivering to loads # Charger current - AC current the FX is taking from AC input and delivering to batteries # Buy current - AC current the FX is taking from AC input and delivering to batteries AND loads # AC input voltage # AC output voltage # Sell current - AC current the FX is delivering from batteries to AC input # FX operational mode (0..10) # FX error mode # FX AC mode # FX Bat Voltage # FX Misc # FX Warnings status.inverter_current = Value(values[0] * imul, units='A', resolution=1) status.chg_current = Value(values[1] * imul, units='A', resolution=1) status.buy_current = Value(values[2] * imul, units='A', resolution=1) status.input_voltage = Value(values[3] * vmul, units='V', resolution=0) status.output_voltage = Value(values[4] * vmul, units='V', resolution=0) status.sell_current = Value(values[5] * imul, units='A', resolution=1) status.operational_mode = values[6] status.error_mode = values[7] status.ac_mode = values[8] status.battery_voltage = Value(values[9] / 10.0, units='V', resolution=1) # values[10]: misc byte status.warnings = values[11] # Also add the raw packet, in case any of the above changes status.raw = data return status
def from_buffer(cls, data): values = cls.fmt.unpack(data) page = MXLogPagePacket() # Parse the mess of binary values page.bat_max = ((values[1] & 0xFC) >> 2) | ((values[2] & 0x0F) << 6) page.bat_min = ((values[9] & 0xC0) >> 6) | (values[10] << 2) | ( (values[11] & 0x03) << 10) page.kilowatt_hours = ((values[2] & 0xF0) >> 4) | (values[3] << 4) page.amp_hours = values[8] | ((values[9] & 0x3F) << 8) page.volts_peak = values[4] page.amps_peak = values[0] | ((values[1] & 0x03) << 8) page.absorb_time = values[5] | ((values[6] & 0x0F) << 8) page.float_time = ((values[6] & 0xF0) >> 4) | (values[7] << 4) page.kilowatts_peak = ((values[12] & 0xFC) >> 2) | (values[11] << 6) page.day = values[13] # Convert to human-readable values page.bat_max = Value(page.bat_max / 10.0, units='V', resolution=1) page.bat_min = Value(page.bat_min / 10.0, units='V', resolution=1) page.volts_peak = Value(page.volts_peak, units='Vpk') page.amps_peak = Value(page.amps_peak / 10.0, units='Apk', resolution=1) page.kilowatts_peak = Value(page.kilowatts_peak / 1000.0, units='kWpk', resolution=3) page.amp_hours = Value(page.amp_hours, units='Ah') page.kilowatt_hours = Value(page.kilowatt_hours / 10.0, units='kWh', resolution=1) page.absorb_time = Value(page.absorb_time, units='min') page.float_time = Value(page.float_time, units='min') # Also add the raw packet page.raw = data return page
def max_battery(self): return Value(self.query(0x000F) / 10.0, units='V', resolution=1)
def voc(self): return Value(self.query(0x0010) / 10.0, resolution=1)
def bat_voltage(self): return Value(self.query(0x0008) / 10.0, units='V', resolution=1)
def panel_voltage(self): return Value(self.query(0x01C6), units='V', resolution=0)
def setpt_absorb(self): return Value(self.query(0x0170) / 10.0, units='V', resolution=1)
def equalize_setpoint(self): return Value(self.query(0x000C) / 10.0, units='V', resolution=1)
def convert_battery_temp(raw_temp): return Value((-0.3576 * raw_temp) + 70.1, units='C', resolution=0)
def total_kah(self): return Value(self.query(0x0014), units='kAh', resolution=1)
def absorb_setpoint(self): return Value(self.query(0x000B) / 10.0, units='V', resolution=1)
def battery_temp_compensated(self): return Value(self.query(0x0016) / 10.0, units='V', resolution=1)
def absorb_time_remaining(self): return Value(self.query(0x0070), units='h', resolution=0)
def float_time_remaining(self): return Value(self.query(0x006E), units='h', resolution=0)
def equalize_time_remaining(self): return Value(self.query(0x0071), units='h', resolution=0)
def max_voc(self): return Value(self.query(0x0012) / 10.0, resolution=1)
def battery_actual(self): return Value(self.query(0x0019) / 10.0, units='V', resolution=1)
def total_kwh_dc(self): return Value(self.query(0x0013), units='kWh', resolution=0)
def charger_kwh(self): return Value(self.query(0x01EA) / 10.0, units='kWh', resolution=1)
def max_wattage(self): return Value(self.query(0x0015), units='W', resolution=0)
def charger_amps_dc(self): return Value(self.query(0x01C7) - 128, units='A', resolution=0)
def setpt_float(self): return Value(self.query(0x0172) / 10.0, units='V', resolution=1)
def refloat_setpoint(self): return Value(self.query(0x000D) / 10.0, units='V', resolution=1)
def charger_watts(self): return Value(self.query(0x016A), units='W', resolution=0)
def sell_current(self): x = self.query(0x006B) if self.is_230v: x /= 2.0 return Value(x, units='A', resolution=1)