def __init__(self, name, inverteraddress='', inverterpincode='0000', timeinverval=10, nodeid=29, packettrace=0): """Initialize interfacer""" # Initialization super(EmonHubSMASolarInterfacer, self).__init__(name) self._btSocket = None self._inverteraddress=inverteraddress self._inverterpincode=inverterpincode self._port=1 self._nodeid=int(nodeid) if packettrace==0: self._packettrace=False else: self._packettrace=True self.MySerialNumber = bytearray([0x08, 0x00, 0xaa, 0xbb, 0xcc, 0xdd]); self._reset_packet_send_counter() self._Inverters = None #Duration in seconds self._time_inverval = int(timeinverval) self._InverterPasswordArray = SMASolar_library.encodeInverterPassword(self._inverterpincode) self._reset_duration_timer() self._reset_time_to_disconnect_timer(); self._log.info("Reading from SMASolar every " + str(self._time_inverval) + " seconds")
def _login_inverter(self): """Log into the SMA solar inverter""" self._log.info("Log into the SMA solar inverter " + str(self._inverteraddress)) self._btSocket = self._open_bluetooth(self._inverteraddress, self._port) #If bluetooth didnt work, exit here if self._btSocket is None: return self._reset_packet_send_counter() self.mylocalBTAddress = SMASolar_library.BTAddressToByteArray(self._btSocket.getsockname()[0], ":") self.mylocalBTAddress.reverse() self._log.debug("initaliseSMAConnection") SMASolar_library.initaliseSMAConnection(self._btSocket, self.mylocalBTAddress, self.MySerialNumber, self._packet_send_counter) self._increment_packet_send_counter() self._increment_packet_send_counter() self._log.debug("logon") SMASolar_library.logon(self._btSocket, self.mylocalBTAddress, self.MySerialNumber, self._packet_send_counter, self._InverterPasswordArray) self._increment_packet_send_counter() self._reset_time_to_disconnect_timer(); self._Inverters={} #TODO: We need to see what packets look like when we get multiple inverters talking to us dictInverterData = SMASolar_library.getInverterDetails(self._btSocket, self._packet_send_counter, self.mylocalBTAddress, self.MySerialNumber) self._increment_packet_send_counter() #Returns dictionary like #{'inverterName': u'SN2120051742\x00\x00', 'serialNumber': 2120051742L, 'ClassName': 'SolarInverter', 'TypeName': 'SB 3000HF-30', 'susyid': 131L, 'Type': 9073L, 'Class': 8001L} self._log.debug(str(dictInverterData)) #Clear rogue characters from name dictInverterData["inverterName"] = re.sub(r'[^a-zA-Z0-9]','', dictInverterData["inverterName"]) nodeName=dictInverterData["inverterName"] #Build list of inverters we communicate with self._Inverters[nodeName] = dictInverterData self._Inverters[nodeName]["NodeId"]=self._nodeid self._log.info("Connected to SMA inverter named [" + self._Inverters[nodeName]["inverterName"] + "] with serial number ["+str(self._Inverters[nodeName]["serialNumber"]) +"] using NodeId="+str(self._Inverters[nodeName]["NodeId"])+ ". Model "+ self._Inverters[nodeName]["TypeName"])
def __init__(self, name, inverteraddress='', inverterpincode='0000', timeinverval=10, nodeid=29, packettrace=0): """Initialize interfacer""" # Initialization super().__init__(name) self._btSocket = None self._inverteraddress = inverteraddress self._inverterpincode = inverterpincode self._port = 1 self._nodeid = int(nodeid) self._btRetrySleepTime = 10 self.no_bluetooth_reported = False self._packettrace = bool(packettrace) # seems a hack & needs explaining why we need this self.MySerialNumber = bytearray([0x08, 0x00, 0xaa, 0xbb, 0xcc, 0xdd]) self._reset_packet_send_counter() self._Inverters = {} #Duration in seconds self._time_inverval = int(timeinverval) self._InverterPasswordArray = SMASolar_library.encodeInverterPassword( self._inverterpincode) self._reset_duration_timer() self._reset_time_to_disconnect_timer() self._log.info("Reading from SMASolar every %d seconds", self._time_inverval)
def read(self): """Read data from inverter and process""" #Wait until we are ready to read from inverter if (self._is_it_time() == False): return self._reset_duration_timer() try: #self._log.debug("Entering read try section") # Check we have a connection already, if not try and obtain one if self._btSocket is None: self._login_inverter() # If bluetooth didn't work, exit here if self._btSocket is None: return readingsToMake = {} readingsToMake["EnergyProduction"] = [ 0x54000200, 0x00260100, 0x002622FF ] #This causes problems with some inverters #readingsToMake["SpotDCPower"]=[0x53800200, 0x00251E00, 0x00251EFF] readingsToMake["SpotACPower"] = [ 0x51000200, 0x00464000, 0x004642FF ] readingsToMake["SpotACTotalPower"] = [ 0x51000200, 0x00263F00, 0x00263FFF ] readingsToMake["SpotDCVoltage"] = [ 0x53800200, 0x00451F00, 0x004521FF ] readingsToMake["SpotACVoltage"] = [ 0x51000200, 0x00464800, 0x004655FF ] readingsToMake["SpotGridFrequency"] = [ 0x51000200, 0x00465700, 0x004657FF ] readingsToMake["OperationTime"] = [ 0x54000200, 0x00462E00, 0x00462FFF ] readingsToMake["InverterTemperature"] = [ 0x52000200, 0x00237700, 0x002377FF ] #Not very useful for reporting #readingsToMake["MaxACPower"]=[0x51000200, 0x00411E00, 0x004120FF] #readingsToMake["MaxACPower2"]=[0x51000200, 0x00832A00, 0x00832AFF] #readingsToMake["GridRelayStatus"]=[0x51800200, 0x00416400, 0x004164FF] #Only useful on off grid battery systems #readingsToMake["ChargeStatus"]=[0x51000200, 0x00295A00, 0x00295AFF] #readingsToMake["BatteryInfo"]=[0x51000200, 0x00491E00, 0x00495DFF] #Get first inverter in dictionary inverter = self._Inverters[self._Inverters.keys()[0]] self._log.debug("Reading from inverter " + inverter["inverterName"]) #Loop through dictionary and take readings, building "output" dictionary as we go output = {} for key in readingsToMake: data = SMASolar_library.request_data( self._btSocket, self._packet_send_counter, self.mylocalBTAddress, self.MySerialNumber, readingsToMake[key][0], readingsToMake[key][1], readingsToMake[key][2], inverter["susyid"], inverter["serialNumber"]) self._increment_packet_send_counter() if data is not None: output.update(SMASolar_library.extract_data(data)) if (self._packettrace): self._log.debug( "Packet reply for " + key + ". Packet from {0:04x}/{1:08x}".format( data.getTwoByte(14), data.getFourByteLong(16))) self._log.debug(data.debugViewPacket()) #Sort the output to keep the keys in a consistant order names = [] values = [] for key in sorted(output): names.append(output[key].Label) values.append(output[key].Value) #self._log.debug("Building cargo") c = Cargo.new_cargo() c.rawdata = None c.realdata = values c.names = names #TODO: We need to revisit this once we know how multiple inverters communicate with us c.nodeid = inverter["NodeId"] c.nodename = inverter["inverterName"] #TODO: We should be able to populate the rssi number from the bluetooth signal strength c.rssi = 0 #Inverter appears to kill our connection every 10 minutes, so disconnect after 8 minutes #to avoid errors in log files if (self._is_it_time_to_disconnect() == True): self._log.info("Disconnecting Bluetooth after timer expired") SMASolar_library.logoff(self._btSocket, self._packet_send_counter, self.mylocalBTAddress, self.MySerialNumber) self._reset_time_to_disconnect_timer() self._btSocket.close() self._btSocket = None self._log.debug("Returning cargo") return c except bluetooth.btcommon.BluetoothError as err1: self._log.error("Bluetooth Error") self._log.error(err1) self._btSocket = None except Exception as err2: exc_type, exc_value, exc_traceback = sys.exc_info() self._log.error(err2) self._log.error( repr( traceback.format_exception(exc_type, exc_value, exc_traceback))) self._btSocket = None