Example #1
0
    def setValues(self, address, values):
        ''' Sets the requested values of the datastore

        :param address: The starting address
        :param values: The new values to be set
        '''
        if not isinstance(values, list):
            values = [values]
        start = address - self.address
        self.values[start:start + len(values)] = values
        if start <= 550 < start + len(values):
            if self.values[500] != values[550-start]:
                logInfo.debug("ModbusMySequentialDataBlock.setValues updating 500({0}) with new value {1}".format(self.values[500],values[550-start]))
                self.values[500] = values[550-start]
        if start <= 552 < start + len(values):
            global g_Time
            global s_Time
            decoder = BinaryPayloadDecoder.fromRegisters(self.values[502:503],endian=Endian.Little)
            bits_502 = decoder.decode_bits()
            bits_502 += decoder.decode_bits()
            decoder = BinaryPayloadDecoder.fromRegisters(self.values[506:507],endian=Endian.Little)
            bits_506 = decoder.decode_bits()
            bits_506 += decoder.decode_bits()
            decoder = BinaryPayloadDecoder.fromRegisters(values[552-start:553-start],endian=Endian.Little)
            bits_552 = decoder.decode_bits()
            bits_552 += decoder.decode_bits()
            logInfo.debug("ModbusMySequentialDataBlock.setValues updating 552({0}) {1}".format(values[552-start], bits_552))
            if bits_552[2]:
                print "ModbusMySequentialDataBlock.setValues start iniettore da remoto"
                logInfo.debug("ModbusMySequentialDataBlock.setValues start iniettore da remoto")
                g_Time = 0
                bits_502[7] = 1 # START INIETTORE
                self.hndlr.pumpStarted = True
                bits_506[2] = 1
                bits_506[3] = 0
                bits_552[2] = 0
                bits_builder = BinaryPayloadBuilder(endian=Endian.Little)
                bits_builder.add_bits(bits_502)
                bits_builder.add_bits(bits_506)
                bits_builder.add_bits(bits_552)
                bits_reg = bits_builder.to_registers()
                self.values[502:503]=[bits_reg[0]]
                self.values[506:507]=[bits_reg[1]]
                self.values[552:553]=[bits_reg[2]]
            if bits_552[3]:
                print "ModbusMySequentialDataBlock.setValues stop iniettore da remoto"
                logInfo.debug("ModbusMySequentialDataBlock.setValues stop iniettore da remoto")
                bits_502[7] = 0 # STOP INIETTORE
                bits_506[2] = 0
                self.hndlr.pumpStarted = False
                bits_506[3] = 1
                bits_552[3] = 0
                bits_builder = BinaryPayloadBuilder(endian=Endian.Little)
                bits_builder.add_bits(bits_502)
                bits_builder.add_bits(bits_506)
                bits_builder.add_bits(bits_552)
                bits_reg=bits_builder.to_registers()
                self.values[502:503]=[bits_reg[0]]
                self.values[506:507]=[bits_reg[1]]
                self.values[552:553]=[bits_reg[2]]
Example #2
0
    def checkPump(self,client_p):
        rr = client_p.read_holding_registers(500,100,unit=1)
        # conversione in bit array da 552
        decoder = BinaryPayloadDecoder.fromRegisters(rr.registers[52:53],endian=Endian.Little)
        bits_552 = decoder.decode_bits()
        bits_552 += decoder.decode_bits()
        bits_552[10] = True
        b_builder = BinaryPayloadBuilder(endian=Endian.Little)
        b_builder.add_bits(bits_552)
        reg_552 = b_builder.to_registers()
        rr.registers[52:53] = reg_552
        for it in range(10):
            self.p_count += 1
            rr.registers[50] = self.p_count
            rq = client_p.write_registers(500, rr.registers,unit=1)
            if rq.function_code < 0x80:
                rr_p = client_p.read_holding_registers(500,100,unit=1)
                if len(rr_p.registers)==100 and rr_p.registers[0]==self.p_count:
                    decoder = BinaryPayloadDecoder.fromRegisters(rr_p.registers[2:7],endian=Endian.Little)
                    # 502
                    bits_502 = decoder.decode_bits()
                    bits_502 += decoder.decode_bits()
                    # 503
                    bits_503 = decoder.decode_bits()
                    bits_503 += decoder.decode_bits()
                    # 504
                    bits_504 = decoder.decode_bits()
                    bits_504 += decoder.decode_bits()
                    # 505
                    bits_505 = decoder.decode_bits()
                    bits_505 += decoder.decode_bits()
                    # 506
                    bits_506 = decoder.decode_bits()
                    bits_506 += decoder.decode_bits()
                    if bits_502[7]:
                        builder.get_object("switchPumpStatus").set_active(True)
                    else:
                        builder.get_object("switchPumpStatus").set_active(False)

                    if bits_502[4] == False and bits_502[10] == True:
                        builder.get_object("switchPumpStatus").set_sensitive(True)
                    else:
                        builder.get_object("switchPumpStatus").set_sensitive(False)
                else:
                    print "errore checkPump %d" % self.p_count
        bits_552[10] = False
        print str(bits_552)
        b_builder = BinaryPayloadBuilder(endian=Endian.Little)
        b_builder.add_bits(bits_552)
        reg_552_2 = b_builder.to_registers()
        rr.registers[52:53] = reg_552_2
        rq = client_p.write_registers(500, rr.registers,unit=1)
        if rq.function_code < 0x80:
            pass
        else:
            print "checkPump terminato con scrittura KO"
Example #3
0
    def on_switchPumpStatus_state_set(self, switch,gparam):
        self.ret_p=self.client_p.connect()
        rr = self.client_p.read_holding_registers(500,100,unit=1)
        # conversione in bit array da 552
        decoder = BinaryPayloadDecoder.fromRegisters(rr.registers[52:53],endian=Endian.Little)
        bits_552 = decoder.decode_bits()
        bits_552 += decoder.decode_bits()

        decoder = BinaryPayloadDecoder.fromRegisters(rr.registers[2:7],endian=Endian.Little)
        # 502
        bits_502 = decoder.decode_bits()
        bits_502 += decoder.decode_bits()
        # 503
        bits_503 = decoder.decode_bits()
        bits_503 += decoder.decode_bits()
        # 504
        bits_504 = decoder.decode_bits()
        bits_504 += decoder.decode_bits()
        # 505
        bits_505 = decoder.decode_bits()
        bits_505 += decoder.decode_bits()
        # 506
        bits_506 = decoder.decode_bits()
        bits_506 += decoder.decode_bits()
        bSendCommand = False
        if switch.get_active():
            # %MW552:X2 START INIET. DA REMOTO
            bSendCommand = not bits_502[7]
            bits_552[2] = True
            bits_552[3] = False
            bits_552[14] = True
        else:
            # %MW552:X2 STOP INIET. DA REMOTO
            bSendCommand = bits_502[7]
            bits_552[2] = False
            bits_552[3] = True
            bits_552[14] = False
        builder = BinaryPayloadBuilder(endian=Endian.Little)
        # builder.add_bits(bits_502)
        builder.add_bits(bits_552)
        reg_552 = builder.to_registers()
        rr.registers[52:53] = reg_552
        self.p_count += 1
        rr.registers[50] = self.p_count
        if bSendCommand:
            self.client_p.write_registers(500, rr.registers,unit=1)
            if bits_552[2]:
                bits_552[2] = False
                builder = BinaryPayloadBuilder(endian=Endian.Little)
                # builder.add_bits(bits_502)
                builder.add_bits(bits_552)
                reg_552 = builder.to_registers()
                self.client_p.write_register(552, reg_552[0])
                print "pulsante rilasciato"

        self.client_p.close()
Example #4
0
    def testPayloadDecoderRegisterFactory(self):
        """ Test the payload decoder reset functionality """
        payload = [1, 2, 3, 4]
        decoder = BinaryPayloadDecoder.fromRegisters(payload, endian=Endian.Little)
        encoded = "\x00\x01\x00\x02\x00\x03\x00\x04"
        self.assertEqual(encoded, decoder.decode_string(8))

        decoder = BinaryPayloadDecoder.fromRegisters(payload, endian=Endian.Big)
        encoded = "\x00\x01\x00\x02\x00\x03\x00\x04"
        self.assertEqual(encoded, decoder.decode_string(8))

        self.assertRaises(ParameterException, lambda: BinaryPayloadDecoder.fromRegisters("abcd"))
Example #5
0
 def on_btnSetPump_clicked(self,button):
     rr_p = self.client_p.read_holding_registers(500,100,unit=1)
     decoder = BinaryPayloadDecoder.fromRegisters(rr_p.registers[52:53],endian=Endian.Little)
     bits_552 = decoder.decode_bits()
     bits_552 += decoder.decode_bits()
     self.pmax = self.adjustPMax.get_value()
     _qmax = self.adjustQMax.get_value()
     self.p_count += 1
     rr_p.registers[50] = self.p_count
     rr_p.registers[60] = int(self.pmax)
     if self.chkPAna.get_active():
         self.qmax = getFlowRateAsVolts(_qmax)
         v = getVoltsFromFlowRate(self.qmax)
         print "_qmax => {0} self.qmax => {1} c => {2}".format(_qmax, self.qmax, v)
         rr_p.registers[64] = self.qmax
         rr_p.registers[62] = int(_qmax/litCiclo)
         bits_552[12] = True
     else:
         self.qmax = _qmax
         rr_p.registers[62] = int(self.qmax)
         rr_p.registers[64] = cicli_volt[int(self.qmax)]
         bits_552[12] = False
     b_builder = BinaryPayloadBuilder(endian=Endian.Little)
     # builder.add_bits(bits_502)
     b_builder.add_bits(bits_552)
     reg_552 = b_builder.to_registers()
     rr_p.registers[52:53] = reg_552
     rr_p = self.client_p.write_registers(500,rr_p.registers,unit=1)
Example #6
0
    def decode(self, formatters, byte_order='big', word_order='big'):
        """
        Decode the register response to known formatters.

        :param formatters: int8/16/32/64, uint8/16/32/64, float32/64
        :param byte_order: little/big
        :param word_order: little/big
        :return: Decoded Value
        """
        # Read Holding Registers (3)
        # Read Input Registers (4)
        # Read Write Registers (23)
        if not isinstance(formatters, (list, tuple)):
            formatters = [formatters]

        if self.function_code not in [3, 4, 23]:
            print_formatted_text(
                HTML("<red>Decoder works only for registers!!</red>"))
            return
        byte_order = (Endian.Little if byte_order.strip().lower() == "little"
                      else Endian.Big)
        word_order = (Endian.Little if word_order.strip().lower() == "little"
                      else Endian.Big)
        decoder = BinaryPayloadDecoder.fromRegisters(self.data.get('registers'),
                                                     byteorder=byte_order,
                                                     wordorder=word_order)
        for formatter in formatters:
            formatter = FORMATTERS.get(formatter)
            if not formatter:
                print_formatted_text(
                    HTML("<red>Invalid Formatter - {}"
                         "!!</red>".format(formatter)))
                return
            decoded = getattr(decoder, formatter)()
            self.print_result(decoded)
Example #7
0
    def checkPump(self,client_p):
        self.p_count += 1
        rq = client_p.write_register(550,self.p_count,unit=1)
        if rq.function_code < 0x80:
            rr_p = client_p.read_holding_registers(500,100,unit=1)
            if len(rr_p.registers)==100 and rr_p.registers[0]==self.p_count:
                decoder = BinaryPayloadDecoder.fromRegisters(rr_p.registers[2:7],endian=Endian.Little)
                # 502
                bits_502 = decoder.decode_bits()
                bits_502 += decoder.decode_bits()
                # 503
                bits_503 = decoder.decode_bits()
                bits_503 += decoder.decode_bits()
                # 504
                bits_504 = decoder.decode_bits()
                bits_504 += decoder.decode_bits()
                # 505
                bits_505 = decoder.decode_bits()
                bits_505 += decoder.decode_bits()
                # 506
                bits_506 = decoder.decode_bits()
                bits_506 += decoder.decode_bits()
                if bits_502[7]:
                    builder.get_object("switchPumpStatus").set_active(True)
                else:
                    builder.get_object("switchPumpStatus").set_active(False)

                if bits_502[4] == False and bits_502[10] == True:
                    builder.get_object("switchPumpStatus").set_sensitive(True)
                else:
                    builder.get_object("switchPumpStatus").set_sensitive(False)                
        self.setPumpFlowAndPressure()
Example #8
0
	def read(self):
		count = COUNTS.get(self.data_type)
		if not count:
			raise ValueError('Unsupported data type {}'.format(self.data_type))

		_logger.debug('read register: {}, count: {}, slave: {}, function: {}'.format(self.register_addr, count, self.slave_id, self.function_code))
		if self.function_code == 3:
			result = self.client.read_holding_registers(self.register_addr, count, unit=self.slave_id)
		elif self.function_code == 4:
			result = self.client.read_input_registers(self.register_addr, count, unit=self.slave_id)
		else:
			raise ValueError('Unsupported function code {}'.format(self.function_code))
		if result is None:
			raise IOError('No modbus reponse')
		if isinstance(result, ExceptionResponse):
			raise IOError(str(result))

		d = BinaryPayloadDecoder.fromRegisters(result.registers, endian=self.endian)

		if self.data_type == '16bit_int':
			value = d.decode_16bit_int()
		elif self.data_type == '16bit_uint':
			value = d.decode_16bit_uint()
		elif self.data_type == '32bit_int':
			value = d.decode_32bit_int()
		elif self.data_type == '32bit_uint':
			value = d.decode_32bit_uint()
		elif self.data_type == '32bit_float':
			value = d.decode_32bit_float()
		elif self.data_type == '64bit_float':
			value = d.decode_64bit_float()
		else:
			raise ValueError('Unsupported data type {}'.format(self.data_type))
		return value
    def requestLoop(self):

        meterreadings = {}

        try:
            if (self.client.connect() is False):
                print('not connected')
                self.client = self.client.connect()
                print('trying to connecto to ' + str(self.pfcIp))
#==============================================================================
#       Read current timestamp from PFC
#==============================================================================
            timestampSys = round(time.time() * 1000)
            result2 = self.client.read_holding_registers(4, 4)
            decoder = BinaryPayloadDecoder.fromRegisters(result2.registers, endian=Endian.Little)
            timestampPFC = decoder.decode_64bit_int()

#==============================================================================
#       Reads the values from modbus registers clamp by clamp
#       and buffers the results in  meterreadings{}
#		It is not possible to read all registers in one request because of the limitation of the Modbus-Message size to 255kb
# 		When the results of all clamps are buffered, they are published
#==============================================================================
            result = self.client.read_coils(16, 4)
            meterreadings = {'shStarr': result.bits[0],
                             'sh4QS': result.bits[1],
                             'speicherSh': result.bits[2],
                             'speicher4QS': result.bits[3]}
#==============================================================================
#        standardize both TimestampPFC and TimestampSYS precision to be millisecond
#==============================================================================
            meterreadingsToCompare = {}
            meterreadingsToCompare = meterreadings
            self.oldState.pop('TimestampPFC', None)
            self.oldState.pop('TimestampSYS', None)
            self.elapsedTime = self.elapsedTime + 1
            if (self.oldState != meterreadingsToCompare) or (self.elapsedTime >= 60):
                self.elapsedTime = 0
                self.oldState = meterreadingsToCompare
                meterreadings['TimestampPFC'] = str(timestampPFC)[0:13]
                meterreadings['TimestampSYS'] = round(time.time() * 1000)
                self.publish(u'eshl.wago.v1.readout.misc.4qs', json.dumps(meterreadings, sort_keys=True))
                self.publish(u'eshl.wago.v2.readout.misc.4qs', meterreadings)
#==============================================================================
#      If there is no connection to the pfc-modbus slave or no connection to the pfc at all
#      the blankDataSet is published
#==============================================================================
#==============================================================================
#         except ConnectionException as connErr:
#              for x in range(0, len(self.clamps)):
#                         meterreadings[self.clamps[x]] = json.dumps(self.blankDataSetGen(), sort_keys=True)
#              self.publish(u'org.eshl.wago.readout.meter.494', json.dumps(meterreadings,sort_keys=True))
#              print(str(connErr))
#==============================================================================
        except Exception as err:

            print("error: {}".format(err), file=sys.stdout)
            traceback.print_exc(file=sys.stdout)
def start_iniettore(p_client):
    b_ok = False
    n_numReg = 5
    # leggo 502 a 506 per verificare bit di controllo
    p_rr = p_client.read_holding_registers(502,n_numReg,unit=1)
    decoder = BinaryPayloadDecoder.fromRegisters(p_rr.registers,endian=Endian.Little)
    reg={}
    regnum = 502
    for i in range(n_numReg):
        bits_50x = decoder.decode_bits()
        bits_50x += decoder.decode_bits()
        reg[regnum+i] = bits_50x
    if reg[502][4]:
        log.error("Pompa in allarme")
    else:
        if reg[502][6]:
            log.debug("Pompa olio on")
            if reg[502][7]:
                log.error("Ciclo Iniettore ON")
            else:
                log.debug("Ciclo Iniettore OFF")
                # %MW502:X10 Macchina pronta per comando remoto
                b_ok = reg[502][10]
                if b_ok:
                    log.debug("Macchina pronta per comando remoto")
                else:
                    log.error(u"Macchina non è pronta per comando remoto")
                b_ok &= check_alarms(reg[504])
                if b_ok:
                    log.debug("...nessun allarme rilevato")
                    p_comandi_remoto = p_client.read_holding_registers(560,3,unit=1)
                    remote_reg = [0]*3
                    remote_reg = p_comandi_remoto.registers
                    log.debug("COMANDO BAR DA REMOTO IMPOSTATO a %d" %  remote_reg[0]) # %MW560  16 bit 0-100 bar	COMANDO BAR DA REMOTO
                    log.debug("COMANDO NUMERO CICLI MINUTO DA REMOTO a %d" %  remote_reg[2]) # %MW562 16 bit < 40	COMANDO NUMERO CICLI MINUTO DA REMOTO
                    remote_reg[0] = DEFAULT_BAR
                    remote_reg[2] = DEFAULT_CICLI
                    rq = p_client.write_registers(560, remote_reg,unit=1)
                    b_ok  = rq.function_code < 0x80     # test that we are not an error
                    if b_ok:
                        bits_552 = [False]*16
                        bits_552[2] = True # %MW552:X2	START INIET. DA REMOTO
                        builder = BinaryPayloadBuilder(endian=Endian.Little)
                        builder.add_bits(bits_552)
                        reg_552 = builder.to_registers()
                        rq = p_client.write_register(552, reg_552[0],unit=1)
                        b_ok  = rq.function_code < 0x80     # test that we are not an error
                    else:
                        log.error("start_iniettore SET Comandi BAR e CICLI REMOTO fallito!")
                else:
                    log.debug("...verificare allarmi rilevati")
        else:
            log.error("Pompa olio OFF")
    return b_ok
Example #11
0
 def __decodeData(self, data):
     """Decode MODBUS data to float
     
     Function decodes a list of MODBUS 32bit float data passed to it
     into its respective list of floats.
     
     Arguments:
     :param data: Data to be decoded
     :type data: list
     """
     returnData = [0]*(len(data)/2)
     decoder = BinaryPayloadDecoder.fromRegisters(data, endian=Endian.Little)
     for i in range(0,len(data)/2):
         returnData[i] = round(decoder.decode_32bit_float(),2)
     return returnData
Example #12
0
def readChannels():
    # voltage phase 1 to neutral
    print "New measurement readings: ", int(time.time())
    listValues = list()
    for c in listChannels:
    	handle = client.read_holding_registers(c['register'],c['words'],unit=c['unit'])
    	# print c['description'], ":"
    	if c['words'] > 1:
    		decoder = BinaryPayloadDecoder.fromRegisters(handle.registers, endian=Endian.Big)
    		value = decoder.decode_32bit_int()/float(c['factor'])
    	else:
    		value = handle.registers[0]/float(c['factor'])
    	#print c['description'], ":", str(value)
    	listValues.append(value)	

    for i, channel in enumerate(listChannels):
    	# print channel['description'],":", channel['uuid'], int(time.time()*1000), listValues[i]
    	# Here fire values into VZ middleware
    	addValue(channel['uuid'], int(time.time()*1000), listValues[i])
Example #13
0
def read_register(client, register):    
    logger.info("---- Read register " + str(register))

    try:
        rr = client.read_holding_registers(register, count=2, unit=1)
        logger.info("Register value are " + str(rr.registers))
        
        # build register
        reg=[0, 0]
        reg[0] = rr.registers[0]
        reg[1] = rr.registers[1]
    
        # decode register 
        decoder = BinaryPayloadDecoder.fromRegisters(reg, endian=Endian.Big)
        decoded = decoder.decode_32bit_float()
        
        logger.info("Register decoded value are " + str(decoded))
        return decoded
    except ConnectionException:
        raise ConnectionExceptionRest("")
    def __get_mc602(self, address):

        try:
            log.debug("Attempting to read from MC602")
            registers = self.read_input_registers( \
                address = address, count = 2, unit = 65)
            log.debug("Successfully read registers from MC602")
            log.debug("Attempting to convert registers")

            # registers are encoded in "big endian", however the attribute
            # to convert to a float value in pymodbus therefore is Little
            # (and not Big as expected)! Details in class Constants/Endian

            decoder = BinaryPayloadDecoder.fromRegisters(registers, \
                endian = Endian.Little)
            float_value = decoder.decode_32bit_float()
            log.debug("Successfully converted registers to float_value")
            
            return float_value

        except:
            log.error("Failed to read from MC602")
Example #15
0
 def on_btnSetPump_clicked(self,button):
     rr_p = self.client_p.read_holding_registers(500,100,unit=1)
     decoder = BinaryPayloadDecoder.fromRegisters(rr_p.registers[52:53],endian=Endian.Little)
     bits_552 = decoder.decode_bits()
     bits_552 += decoder.decode_bits()
     self.pmax = self.adjustPMax.get_value()
     self.qmax = self.adjustQMax.get_value()
     self.p_count += 1
     rr_p.registers[50] = self.p_count
     rr_p.registers[60] = int(self.pmax)
     if self.chkPAna.get_active():
         rr_p.registers[64] = int(self.qmax)
         # TODO rr_p.registers[62] = equivalente mappato
         bits_552[12] = True
     else:
         rr_p.registers[62] = int(self.qmax)
         rr_p.registers[64] = cicli_volt[int(self.qmax)]
         bits_552[12] = False
     b_builder = BinaryPayloadBuilder(endian=Endian.Little)
     # builder.add_bits(bits_502)
     b_builder.add_bits(bits_552)
     reg_552 = b_builder.to_registers()
     rr_p.registers[52:53] = reg_552
     rr_p = self.client_p.write_registers(500,rr_p.registers,unit=1)
    def read(self):
        for x in self.queue[self.current]:
            try:
                t = util.now()
                self.res = self.client.read_holding_registers(3900, 100, unit=x.Id)

                if (self.res == None):
                    continue

                for y in xrange(0, len(self.parameters[x.Model])):
                    read_reg = self.reading_registers[x.Model][y]
                    if (read_reg == 92 or read_reg == 98):
                        decoder = BinaryPayloadDecoder.fromRegisters(self.res.registers[read_reg:read_reg + 2],
                                                                     endian=Endian.Big)
                        value = decoder.decode_32bit_uint()
                    else:
                        value = convert((self.res.registers[read_reg + 1] << 16) + self.res.registers[read_reg])
                    self.add('/Meter' + str(x.Id) + '/' + self.parameters[x.Model][y], t, value)

            except SerialException:
                print "Serial Exception encountered. Looking for new tty port."
                self.client = self.CONNECT_TO_METER()

        pop_count = len(self.queue[self.current])
        for x in xrange(0, pop_count):
            popped = self.queue[self.current].pop(0)
            next_index = (self.current + popped.Rate) % self.SLOWEST_POSSIBLE_RATE

            while (len(self.queue[next_index]) == 2):
                next_index += 1
                if (next_index == self.SLOWEST_POSSIBLE_RATE):
                    next_index = 0

            self.queue[next_index].append(popped)

        self.current = (self.current + 1) % self.SLOWEST_POSSIBLE_RATE
Example #17
0
    def on_btnShow_clicked(self,button):
        # show dlgRegistries
        self.lstDialog = builder.get_object("dlgRegistries")
        self.liststore = builder.get_object("liststore1")
        if not self.ret_p:
            self.ret_p = self.client_p.connect()
        if self.ret_p:
            self.liststore.clear()
            rr = self.client_p.read_holding_registers(500,100,unit=1)
            for idx in [0,2,4,6,12,13,14,15,16,20,50,52,60,62]:
                if idx in (2,4,6,52):
                    decoder = BinaryPayloadDecoder.fromRegisters(rr.registers[idx:idx+1],endian=Endian.Little)
                    bits = decoder.decode_bits()
                    bits += decoder.decode_bits()
                    for ib, b in enumerate(bits):
                        if b:
                            sCode = "%MW5{0:02d}:X{1}".format(idx,ib)
                            self.liststore.append([sCode,reg_descr[sCode], str( b ) ])
                else:
                    sCode = "%MW5{0:02d}".format(idx)
                    self.liststore.append([sCode, reg_descr[sCode], str( rr.registers[idx]) ])    
        response = self.lstDialog.run()

        self.lstDialog.hide()
Example #18
0
def get_pv_data(config):
    host = config.get('inv_host')
    port = config.get('inv_port', 502)
    modbusid = config.get('inv_modbus_id', 3)
    manufacturer = config.get('inv_manufacturer', 'Default')
    # registers = [ ['30057', 'U32', 'RAW', 'serial', ''], ['30201','U32','ENUM','Status',''], ['30051','U32','ENUM','DeviceClass',''], ['30053','U32','ENUM','DeviceID',''], ['40631', 'STR32', 'UTF8', 'Device Name', ''], ['30775', 'S32', 'FIX0', 'AC Power', 'W'], ['30813', 'S32', 'FIX0', 'AC apparent power', 'VA'], ['30977', 'S32', 'FIX3', 'AC current', 'A'], ['30783', 'S32', 'FIX2', 'AC voltage', 'V'], ['30803', 'U32', 'FIX2', 'grid frequency', 'Hz'], ['30773', 'S32', 'FIX0', 'DC power', 'W'], ['30771', 'S32', 'FIX2', 'DC input voltage', 'V'], ['30777', 'S32', 'FIX0', 'Power L1', 'W'], ['30779', 'S32', 'FIX0', 'Power L2', 'W'], ['30781', 'S32', 'FIX0', 'Power L3', 'W'], ['30953', 'S32', 'FIX1', u'device temperature', u'\xb0C'], ['30517', 'U64', 'FIX3', 'daily yield', 'kWh'], ['30513', 'U64', 'FIX3', 'total yield', 'kWh'], ['30521', 'U64', 'FIX0', 'operation time', 's'], ['30525', 'U64', 'FIX0', 'feed-in time', 's'], ['30975', 'S32', 'FIX2', 'intermediate voltage', 'V'], ['30225', 'S32', 'FIX0', 'Isolation resistance', u'\u03a9'] ]
    registerconfig = config.get('registers')
    registers = None
    if registerconfig:
        registers = eval(registerconfig)
    if None in (registers, host, port, modbusid):
        print("Modbus: missing modbus parameter inv_")
        return None

    client = ModbusClient(host=host, port=port)
    try:
        client.connect()
    except:
        print('Modbus Connection Error',
              'could not connect to target. Check your settings, please.')
        return None

    data = {}  ## empty data store for current values

    for myreg in registers:
        ## if the connection is somehow not possible (e.g. target not responding)
        #  show a error message instead of excepting and stopping
        try:
            addr = int(myreg[0])
            dt = myreg[1]
            received = client.read_input_registers(address=addr,
                                                   count=modbusdatatype[dt],
                                                   unit=int(modbusid))
        except Exception as e:
            thisdate = str(datetime.datetime.now()).partition('.')[0]
            thiserrormessage = thisdate + 'Modbus: Connection not possible. Check settings or connection.'
            print(thiserrormessage)
            print(traceback.format_exc())
            return None  ## prevent further execution of this function

        name = myreg[3]
        message = BinaryPayloadDecoder.fromRegisters(received.registers,
                                                     byteorder=Endian.Big,
                                                     wordorder=Endian.Big)
        ## provide the correct result depending on the defined datatype
        if myreg[1] == 'S32':
            interpreted = message.decode_32bit_int()
        elif myreg[1] == 'U32':
            interpreted = message.decode_32bit_uint()
        elif myreg[1] == 'U64':
            interpreted = message.decode_64bit_uint()
        elif myreg[1] == 'STR32':
            interpreted = message.decode_string(32)
        elif myreg[1] == 'S16':
            interpreted = message.decode_16bit_int()
        elif myreg[1] == 'U16':
            interpreted = message.decode_16bit_uint()
        else:  ## if no data type is defined do raw interpretation of the delivered data
            interpreted = message.decode_16bit_uint()

        ## check for "None" data before doing anything else
        if ((interpreted == MIN_SIGNED) or (interpreted == MAX_UNSIGNED)):
            value = None
        else:
            ## put the data with correct formatting into the data table
            if myreg[2] == 'FIX3':
                value = float(interpreted) / 1000
            elif myreg[2] == 'FIX2':
                value = float(interpreted) / 100
            elif myreg[2] == 'FIX1':
                value = float(interpreted) / 10
            elif myreg[2] == 'UTF8':
                value = str(interpreted, 'UTF-8').rstrip("\x00")
            elif myreg[2] == 'ENUM':
                e = pvenums.get(name, {})
                value = e.get(interpreted, str(interpreted))
            else:
                value = interpreted
        data[name] = value

    client.close()
    return data
Example #19
0
 def __get_mc602(self, address):
         registers = self.read_input_registers(address = address, count = 2, unit = 65)
         decoder = BinaryPayloadDecoder.fromRegisters(registers, endian = Endian.Little)
         float_value = decoder.decode_32bit_float()
         return float_value
Example #20
0
modbus = ModbusClient(method='rtu', port='/dev/ttyUSB0', baudrate=2400, timeout=1)
modbus.connect()
with open('log.csv','w') as f:
	thewriter=csv.writer(f)

 	thewriter.writerow(['year,month,date,hr:min:sec:ms,frequency     ','voltage     ','current    '])
	
	while True:
                
		v = modbus.read_input_registers(0x00,2 , unit=1)
		f = modbus.read_input_registers(0x46,2 , unit=1)
		i = modbus.read_input_registers(0x06,2 , unit=1)
	        now= datetime.datetime.now()
		
	        print(now.strftime("-------%Y-%m-%d %H:%M:%S----------"))
		decoder = BinaryPayloadDecoder.fromRegisters(v.registers,byteorder=Endian.Big)
	                                             
		v1=decoder.decode_32bit_float()
	        print ("voltage is ", v1, "V")
		
		decoder = BinaryPayloadDecoder.fromRegisters(f.registers,byteorder=Endian.Big)
		f1=decoder.decode_32bit_float()
		print ("frequency is ",f1, "hz")
		
		decoder = BinaryPayloadDecoder.fromRegisters(i.registers,byteorder=Endian.Big)
		i1=decoder.decode_32bit_float()
		print ("current is ", i1, "I")
	        print""

		thewriter.writerow([now,f1,v1,i1])
	
Example #21
0
def adquisicion():

    while True:
        #	tic = tm.default_timer()
        #Inicializacion de variables antes de entrar al loop y obtener los promedios
        IpanelT = 0
        VpanelT = 0
        VpanelV = 0

        IcargaT = 0
        VcargaT = 0

        IbatT = 0
        VbatT = 0

        Vsensor = 0

        for j in range(501):

            ##potencia del panel solar

            Ipanel = mcp.read_adc(7)  ## Corriente del panel solar
            Ipanel = ((Ipanel) * (5.15 / 1023))
            #IpanelV=IpanelV+Ipanel
            Ipanel = Ipanel + 0.03
            #Ipanel=(-25.3+10*Ipanel)-0.2
            Ipanel = (-2.6 + Ipanel) * (1 / 0.09693)
            if Ipanel > 0:
                IpanelT = IpanelT + Ipanel  ## Suma de corriente del panel solar sin promediar

            Vpanel = mcp.read_adc(4)
            Vpanel = Vpanel * (5.15 / 1023)
            VpanelV = VpanelV + Vpanel
            #Vpanel=Vpanel*(37.5/7.5)  ## voltaje del panel solar
            Vpanel = 4.093 * Vpanel + 3.4444
            VpanelT = VpanelT + Vpanel  #  Suma de voltaje del panel solar sin promediar

            ## potencia de la carga
            Vcarga = mcp.read_adc(6)
            Vcarga = ((Vcarga) * (5.15 / 1023)) * (37000.0 / 7500.0)
            VcargaT = VcargaT + Vcarga
            Icarga = mcp.read_adc(0)  ##
            Icarga = round(((Icarga) * (5.15 / 1023)),
                           2)  ## voltaje desde el MCP
            #S_5=(-25.3+10*S_5m)-0.2
            Icarga = (-2.54 + Icarga) * (1 / 0.095
                                         )  ## calculo de corriente de la carga
            IcargaT = IcargaT + Icarga

            ## potencia de la bateria
            Ibat = mcp.read_adc(1)
            Ibat = ((Ibat) * (5.15 / 1023))
            #Vsensor=Vsensor+Ibat
            #Ibat=(-2.54+Ibat)*(1/0.1852)
            IbatT = IbatT + Ibat
            Vbat = mcp.read_adc(5)
            Vbat = ((Vbat) * (5.15 / 1023)) * (37000.0 / 7500.0)
            VbatT = VbatT + Vbat

            #j=j+1

    #	toc = tm.default_timer()
    ## potencia del panel solar
        PStotal = round(((IpanelT) * ((VpanelT) + 0.5) / j) / j,
                        2)  ## potencia del panel solar promedio

        ## potencia de la carga
        IcargaT = (IcargaT / j) - 0.2
        PLtotal = (VcargaT / j) * IcargaT
        #PLtotal=round((-6.96327 + 0.742732*PLtotal + 0.00062677*PLtotal*PLtotal)+2,2)
        PLtotal = round(
            (4.80352 + 0.624629 * PLtotal + 0.000745302 * PLtotal * PLtotal),
            2)

        ## potencia de la bateria
        IbatT = IbatT / j

        if IbatT < 2.4:
            IbatT = 6 * IbatT - 14.28
        elif IbatT > 2.46:
            IbatT = 5 * IbatT - 11.86
        else:
            Ibat = 0

        PBtotal = round((IbatT * VbatT) / (j), 2) - 13
        #print(IbatT/j)

        if PLtotal < 2:
            PLtotal = 0

        elif PStotal < 2:
            PStotal = 0

        result = client.read_holding_registers(11729, 2,
                                               unit=1)  #Current A 1100
        decoder = BinaryPayloadDecoder.fromRegisters(result.registers,
                                                     byteorder=Endian.Big)
        PTred = decoder.decode_32bit_float()
        sw = 1

        return PTred, PStotal, PBtotal, PLtotal
Example #22
0
 def __read_s16(self, adr_dec):
     result = self.client.read_holding_registers(adr_dec, 1, unit=71)
     s16_value = BinaryPayloadDecoder.fromRegisters(result.registers, byteorder=Endian.Big,wordorder=Endian.Little)
     return s16_value.decode_16bit_uint()
Example #23
0
    def read(self, iO='in'):
        #print('DATEN VOM BUS LESEN')
        i = 0
        if iO !='in':
            x = 'out'
        else:
            x = 'in'
        try:
            for byte in self._db[x]:
                rr = self._modbuspy.read_holding_registers(byte,2)
                pprint(rr)
                decodert2 = BinaryPayloadDecoder.fromRegisters(rr.registers, endian=Endian.Little)
                ##prüfen welcher dpt typ vorliegt und  dann das registerabfrage ergebnis aufdröseln:
                #->decode_16bit_uint()  -> 7 / 8
                #->decode_8bit_uint()   -> 5 | 5.001
                #->decode_8bit_int()    -> 6
                #->decode_bits()        -> 1
                for bit in self._db[x][byte]:                                                    ##eintraege in dict durchgehen
                    bitpos = bit[0]
                    type =  bit[1]
                    name =  bit[3]
                    
                    if type == '5' or type == '5.001' or type == '6':                                              ##8bit uint / int
                        length = 8
                        
                        if type == '6':
                            lb = decodert2.decode_8bit_int()
                            hb = decodert2.decode_8bit_int()
                            
                        elif type == '5' or type == '5.001':
                            lb = decodert2.decode_8bit_uint()
                            hb = decodert2.decode_8bit_uint()
                            
                        if bitpos < 8:#lb
                            value = hb
                            #logger.debug('MODBUS: byte{0} startpos{1} wert (5) {2}'.format(bit, bitpos,value)) 
                        else:#hb
                            value = lb
                            #logger.debug('MODBUS: byte{0} startpos{1} wert (5) {2}'.format(bit, bitpos,value)) 
                        
                        if type == '5.001':
                            #print('lb/hb Daten gelesen', value)
                            value = self.en5001(value)
                            #logger.debug('MODBUS: byte{0} startpos{1} wert (5.001) {2}'.format(bit, bitpos, value)) 
                    elif type == '7' or type == '8':                                                #16bit uint / int
                        length = 16
                        if type == '7':                                                             #0...65535
                            value = decodert2.decode_16bit_uint()
                            #logger.debug('MODBUS: 16bit uint{0}'.format(value)) 
                        else:                                                                       #-32768...32767
                            value  = decodert2.decode_16bit_int()    
                            #logger.debug('MODBUS: 16bit int{0}'.format(value)) 
                        
                    elif type == '1':
                        length = 1
                        hb = decodert2.decode_bits()
                        lb = decodert2.decode_bits()
                        bits = lb+hb
                     
                        value = bits[bitpos]
                        #logger.debug('MODBUS: Bits{0}'.format(bits))   
                        
                    bit[2] = value                                                                  #zurückspeichern   
                    
                    decodert2.reset() 
            ##Debug#################################################################################
                    bit[3](value, caller='modbus')
                i = i+1
                lb = decodert2.decode_bits()
                hb = decodert2.decode_bits()
                bits = hb+lb
                decodert2.reset() 
                logger.debug('MODBUS: read from PLC {0}-{1} {2}'.format(byte, bits, bytes))

        except Exception as e:
            logger.error('MODBUS: Could not read an InputWord, because {}'.format( e))
            self._lock.release()
            return None
        i = 0
        return None        
Example #24
0
    async def modbus_loop(self):
        while True:
            sleep(0.005)
            try:

                reading = self._client.read_holding_registers(40069, 39)
                if reading:
                    data = BinaryPayloadDecoder.fromRegisters(
                        reading, byteorder=Endian.Big, wordorder=Endian.Big)

                    data.skip_bytes(4)
                    #data.decode_16bit_uint()
                    #data.decode_16bit_uint()

                    #40072-40075
                    ac_total_current = data.decode_16bit_uint()
                    ac_current_phase_a = data.decode_16bit_uint()
                    ac_current_phase_b = data.decode_16bit_uint()
                    ac_current_phase_c = data.decode_16bit_uint()

                    #40076
                    ac_current_scalefactor = 10**data.decode_16bit_int()

                    values['ac_total_current'] = self.round(
                        ac_total_current * ac_current_scalefactor)
                    values['ac_current_phase_a'] = self.round(
                        ac_current_phase_a * ac_current_scalefactor)
                    values['ac_current_phase_b'] = self.round(
                        ac_current_phase_b * ac_current_scalefactor)
                    values['ac_current_phase_c'] = self.round(
                        ac_current_phase_c * ac_current_scalefactor)

                    #40077-40079, AC Voltage AB, BC and CA
                    ac_voltage_phase_ab = data.decode_16bit_uint()
                    ac_voltage_phase_bc = data.decode_16bit_uint()
                    ac_voltage_phase_ca = data.decode_16bit_uint()

                    #40080-40082, AC Voltage AN, BN and CN
                    ac_voltage_phase_a = data.decode_16bit_uint()
                    ac_voltage_phase_b = data.decode_16bit_uint()
                    ac_voltage_phase_c = data.decode_16bit_uint()

                    #40083
                    ac_voltage_phase_scalefactor = 10**data.decode_16bit_int()

                    values['ac_voltage_phase_ab'] = self.round(
                        ac_voltage_phase_ab * ac_voltage_phase_scalefactor)
                    values['ac_voltage_phase_bc'] = self.round(
                        ac_voltage_phase_bc * ac_voltage_phase_scalefactor)
                    values['ac_voltage_phase_ca'] = self.round(
                        ac_voltage_phase_ca * ac_voltage_phase_scalefactor)

                    values['ac_voltage_phase_a'] = self.round(
                        ac_voltage_phase_a * ac_voltage_phase_scalefactor)
                    values['ac_voltage_phase_b'] = self.round(
                        ac_voltage_phase_b * ac_voltage_phase_scalefactor)
                    values['ac_voltage_phase_c'] = self.round(
                        ac_voltage_phase_c * ac_voltage_phase_scalefactor)

                    #40084
                    ac_power_output = data.decode_16bit_int()

                    #40085
                    ac_power_scalefactor = 10**data.decode_16bit_int()
                    values['ac_power_output'] = self.round(
                        ac_power_output * ac_power_scalefactor)

                    #40086 frequency
                    freq = data.decode_16bit_uint()
                    freq_scalefactor = 10**data.decode_16bit_int()
                    values['ac_frequency'] = self.round(freq *
                                                        freq_scalefactor)

                    #AC VA
                    ac_va = data.decode_16bit_int()
                    ac_va_scalefactor = 10**data.decode_16bit_int()
                    values['ac_va'] = self.round(ac_va * ac_va_scalefactor)

                    #AC VAR
                    ac_var = data.decode_16bit_int()
                    ac_var_scalefactor = 10**data.decode_16bit_int()
                    values['ac_var'] = self.round(ac_var * ac_var_scalefactor)

                    #AC PF
                    ac_pf = data.decode_16bit_int()
                    ac_pf_scalefactor = 10**data.decode_16bit_int()
                    values['ac_pf'] = self.round(ac_pf * ac_pf_scalefactor)

                    #40094
                    lifetime = data.decode_32bit_uint()

                    #40095
                    lifetimeScaleFactor = 10**data.decode_16bit_uint()

                    #Total production entire lifetime
                    values['ac_lifetimeproduction'] = self.round(
                        lifetime * lifetimeScaleFactor)

                    #40097 DC Current
                    dc_current = data.decode_16bit_uint()
                    dc_current_scalefactor = 10**data.decode_16bit_int()
                    values['dc_current'] = self.round(dc_current *
                                                      dc_current_scalefactor)

                    #40099 DC Voltage
                    dc_voltage = data.decode_16bit_uint()
                    dc_voltage_scalefactor = 10**data.decode_16bit_int()
                    values['dc_voltage'] = self.round(dc_voltage *
                                                      dc_voltage_scalefactor)

                    #40101 DC Power input
                    dc_power = data.decode_16bit_int()
                    dc_power_scalefactor = 10**data.decode_16bit_int()
                    values['dc_power_input'] = self.round(dc_power *
                                                          dc_power_scalefactor)

                    #skip some bytes to read heat sink temperature and scale factor
                    data.skip_bytes(2)
                    temp_sink = data.decode_16bit_int()
                    data.skip_bytes(4)
                    temp_sink_scalefactor = 10**data.decode_16bit_int()
                    values['heat_sink_temperature'] = self.round(
                        temp_sink * temp_sink_scalefactor)

                    #40108 Status
                    values['status'] = data.decode_16bit_uint()

                    #calculate efficiency
                    if values['dc_power_input'] > 0:
                        values['computed_inverter_efficiency'] = self.round(
                            values['ac_power_output'] /
                            values['dc_power_input'] * 100)
                    else:
                        values['computed_inverter_efficiency'] = 0

                    #debug-print entire dictionary
                    #for x in values.keys():
                    #    print(x +" => " + str(values[x]))

                    # Skip if increamenting counter has gone to 0, or become too large, this happens on inverter startup
                    validValue = values['ac_lifetimeproduction'] > 0
                    try:
                        float(values['ac_lifetimeproduction'])
                    except Exception as e:
                        validValue = False

                    if validValue:
                        #main state is power production, other values can be fetched as attributes
                        self._state = values['ac_power_output']
                        self._device_state_attributes = values

                        #tell HA there is new data
                        self.async_schedule_update_ha_state()

                else:
                    if self._client.last_error() > 0:
                        _LOGGER.error(f'error {self._client.last_error()}')

            except Exception as e:
                _LOGGER.error(f'exception: {e}')
                print(traceback.format_exc())

            await asyncio.sleep(self._scan_interval)
Example #25
0
 def __read_float(self, adr_dec):
     result = self.client.read_holding_registers(adr_dec, 2, unit=71)
     float_value = BinaryPayloadDecoder.fromRegisters(result.registers,byteorder=Endian.Big,wordorder=Endian.Little)
     return round(float_value.decode_32bit_float(), 2)
Example #26
0
    async def modbus_loop(self):
        while True:
            sleep(0.005)
            try:

                reading = self._client.read_holding_registers(40188, 107)

                if reading:
                    data = BinaryPayloadDecoder.fromRegisters(
                        reading, byteorder=Endian.Big, wordorder=Endian.Big)

                    # Identification
                    # 40188 C_SunSpec_DID (unit16)
                    # 40189 C_SunSpec_Length (unit16)
                    data.skip_bytes(4)

                    # Current
                    # #40190 - #40193
                    m1_ac_current = data.decode_16bit_int()
                    m1_ac_current_phase_a = data.decode_16bit_int()
                    m1_ac_current_phase_b = data.decode_16bit_int()
                    m1_ac_current_phase_c = data.decode_16bit_int()

                    # #40194
                    m1_ac_current_scalefactor = 10**data.decode_16bit_int()

                    meter1_values['ac_current'] = self.round(
                        m1_ac_current * m1_ac_current_scalefactor)
                    meter1_values['ac_current_phase_a'] = self.round(
                        m1_ac_current_phase_a * m1_ac_current_scalefactor)
                    meter1_values['ac_current_phase_b'] = self.round(
                        m1_ac_current_phase_b * m1_ac_current_scalefactor)
                    meter1_values['ac_current_phase_c'] = self.round(
                        m1_ac_current_phase_c * m1_ac_current_scalefactor)

                    ################
                    # Voltage
                    ################

                    #40195-40198, AC Voltage LN, AB, BC and CA
                    m1_ac_voltage_phase_ln = data.decode_16bit_uint()
                    m1_ac_voltage_phase_an = data.decode_16bit_uint()
                    m1_ac_voltage_phase_bn = data.decode_16bit_uint()
                    m1_ac_voltage_phase_cn = data.decode_16bit_uint()

                    #40199-40202, AC Voltage LN, AN, BN and CN
                    m1_ac_voltage_phase_ll = data.decode_16bit_uint()
                    m1_ac_voltage_phase_ab = data.decode_16bit_uint()
                    m1_ac_voltage_phase_bc = data.decode_16bit_uint()
                    m1_ac_voltage_phase_ca = data.decode_16bit_uint()

                    #40203
                    m1_ac_voltage_phase_scalefactor = 10**data.decode_16bit_int(
                    )

                    meter1_values['ac_voltage_phase_ll'] = self.round(
                        m1_ac_voltage_phase_ll *
                        m1_ac_voltage_phase_scalefactor)
                    meter1_values['ac_voltage_phase_ab'] = self.round(
                        m1_ac_voltage_phase_ab *
                        m1_ac_voltage_phase_scalefactor)
                    meter1_values['ac_voltage_phase_bc'] = self.round(
                        m1_ac_voltage_phase_bc *
                        m1_ac_voltage_phase_scalefactor)
                    meter1_values['ac_voltage_phase_ca'] = self.round(
                        m1_ac_voltage_phase_ca *
                        m1_ac_voltage_phase_scalefactor)

                    meter1_values['ac_voltage_phase_ln'] = self.round(
                        m1_ac_voltage_phase_ln *
                        m1_ac_voltage_phase_scalefactor)
                    meter1_values['ac_voltage_phase_an'] = self.round(
                        m1_ac_voltage_phase_an *
                        m1_ac_voltage_phase_scalefactor)
                    meter1_values['ac_voltage_phase_bn'] = self.round(
                        m1_ac_voltage_phase_bn *
                        m1_ac_voltage_phase_scalefactor)
                    meter1_values['ac_voltage_phase_cn'] = self.round(
                        m1_ac_voltage_phase_cn *
                        m1_ac_voltage_phase_scalefactor)

                    #40204, Frequency
                    m1_ac_frequency = data.decode_16bit_int()

                    ################
                    # Power
                    ################

                    #40205
                    m1_ac_frequency_scalefactor = 10**data.decode_16bit_int()
                    meter1_values['ac_frequency'] = self.round(
                        m1_ac_frequency * m1_ac_frequency_scalefactor)

                    #40206
                    m1_ac_power_output = data.decode_16bit_int()

                    data.skip_bytes(6)  # Skip the phases

                    #40210
                    m1_ac_power_scalefactor = 10**data.decode_16bit_int()
                    meter1_values['ac_power_output'] = self.round(
                        m1_ac_power_output * m1_ac_power_scalefactor)

                    #40211 Apparent Power
                    m1_ac_va = data.decode_16bit_uint()

                    data.skip_bytes(6)  # Skip the phases

                    m1_ac_va_scalefactor = 10**data.decode_16bit_int()
                    meter1_values['ac_va'] = self.round(m1_ac_va *
                                                        m1_ac_va_scalefactor)

                    #40216 Reactive Power
                    m1_ac_var = data.decode_16bit_uint()

                    data.skip_bytes(6)  # Skip the phases

                    m1_ac_var_scalefactor = 10**data.decode_16bit_int()
                    meter1_values['ac_var'] = self.round(m1_ac_var *
                                                         m1_ac_var_scalefactor)

                    #40221 Power Factor
                    m1_ac_pf = data.decode_16bit_uint()

                    data.skip_bytes(6)  # Skip the phases

                    m1_ac_pf_scalefactor = 10**data.decode_16bit_int()
                    meter1_values['ac_pf'] = self.round(m1_ac_pf *
                                                        m1_ac_pf_scalefactor)

                    ################
                    # Accumulated Energy
                    ################

                    # Real Energy
                    # ---------------

                    #40226
                    m1_exported = data.decode_32bit_uint()
                    data.skip_bytes(12)  # Skip phases

                    #40234
                    m1_imported = data.decode_32bit_uint()
                    data.skip_bytes(12)  # Skip phases

                    #40095
                    m1_energy_scalefactor = 10**data.decode_16bit_uint()

                    # Total production entire lifetime
                    meter1_values['exported'] = self.round(
                        m1_exported * m1_energy_scalefactor)
                    meter1_values['imported'] = self.round(
                        m1_imported * m1_energy_scalefactor)

                    # Apparent Energy
                    # ---------------

                    #40243
                    m1_exported_va = data.decode_32bit_uint()
                    data.skip_bytes(12)  # Skip phases

                    #40251
                    m1_imported_va = data.decode_32bit_uint()
                    data.skip_bytes(12)  # Skip phases

                    #40259
                    m1_energy_va_scalefactor = 10**data.decode_16bit_uint()

                    # Total production entire lifetime
                    meter1_values['exported_va'] = self.round(
                        m1_exported_va * m1_energy_va_scalefactor)
                    meter1_values['imported_va'] = self.round(
                        m1_imported_va * m1_energy_va_scalefactor)

                    # Reactive Energy
                    # ---------------

                    #40260
                    m1_imported_var_q1 = data.decode_32bit_uint()
                    data.skip_bytes(12)  # Skip phases

                    #40268
                    m1_imported_var_q2 = data.decode_32bit_uint()
                    data.skip_bytes(12)  # Skip phases

                    #40276
                    m1_exported_var_q3 = data.decode_32bit_uint()
                    data.skip_bytes(12)  # Skip phases

                    #40284
                    m1_exported_var_q4 = data.decode_32bit_uint()
                    data.skip_bytes(12)  # Skip phases

                    #40293
                    m1_energy_var_scalefactor = 10**data.decode_16bit_uint()

                    # Total production entire lifetime
                    meter1_values['imported_var_q1'] = self.round(
                        m1_imported_var_q1 * m1_energy_var_scalefactor)
                    meter1_values['imported_var_q2'] = self.round(
                        m1_imported_var_q2 * m1_energy_var_scalefactor)
                    meter1_values['exported_var_q3'] = self.round(
                        m1_exported_var_q3 * m1_energy_var_scalefactor)
                    meter1_values['exported_var_q4'] = self.round(
                        m1_exported_var_q4 * m1_energy_var_scalefactor)

                    # Events
                    # ---------------

                    #40097
                    m1_events = data.decode_32bit_uint()
                    meter1_values['events'] = m1_events

                    # M_EVENT_Power_Failure 0x00000004 Loss of power or phase
                    # M_EVENT_Under_Voltage 0x00000008 Voltage below threshold (Phase Loss)
                    # M_EVENT_Low_PF 0x00000010 Power Factor below threshold (can indicate miss-associated voltage and current inputs in three phase systems)
                    # M_EVENT_Over_Current 0x00000020 Current Input over threshold (out of measurement range)
                    # M_EVENT_Over_Voltage 0x00000040 Voltage Input over threshold (out of measurement range)
                    # M_EVENT_Missing_Sensor 0x00000080 Sensor not connected

                    # Skip if incrementing counters have gone to 0, means something isn't right, usually happens on inverter startup
                    validValue = meter1_values[
                        'exported'] > 0 and meter1_values['imported'] > 0
                    if validValue:
                        self._state = meter1_values['ac_power_output']
                        self._device_state_attributes = meter1_values

                        #tell HA there is new data
                        self.async_schedule_update_ha_state()

                else:
                    if self._client.last_error() > 0:
                        _LOGGER.error(f'error {self._client.last_error()}')

            except Exception as e:
                _LOGGER.error(f'exception: {e}')
                print(traceback.format_exc())

            await asyncio.sleep(self._scan_interval)
Example #27
0
#!/usr/bin/env python
from pymodbus.constants import Defaults
from pymodbus.constants import Endian
from pymodbus.client.sync import ModbusTcpClient as ModbusClient
from pymodbus.payload import BinaryPayloadDecoder

Defaults.Timeout = 25
Defaults.Retries = 5
client = ModbusClient('ipaddress.of.venus', port='502')
result = client.read_input_registers(806, 2)
# If you get this error: "unexpected keyword argument 'endian'" try replacing
# `endian=Endian.Big`
#with
# `byteorder=Endian.Big`
# on this line:
decoder = BinaryPayloadDecoder.fromRegisters(result.registers,
                                             endian=Endian.Big)
relay1 = decoder.decode_16bit_uint()
relay2 = decoder.decode_16bit_uint()
print("Relay1: %d, Relay2: %d" % (relay1, relay2))
Example #28
0
 def __read_u64(self, adr_dec):
     result = self.client.read_holding_registers(adr_dec, 4, unit=71)
     u64_value = BinaryPayloadDecoder.fromRegisters(result.registers,
                                                    byteorder=Endian.Big,
                                                    wordorder=Endian.Big)
     return round((u64_value.decode_64bit_uint() * 0.0001), 2)
Example #29
0
    def requestLoop(self):

        numberOfRegPerClamp = 74  # max number of holding registers is 125 as the total number of bytes incl. CRC is 256 according to the spec (via 03 command)
        meterreadings = {}
        meterreadingsV2 = {}
        print(time.time())

        try:
            if (self.client.connect() is False):
                print('not connected')
                self.client = self.client.connect()
                print('trying to connecto to ' + str(self.pfcIp))
            address = 0
#==============================================================================
#       Read current timestamp from PFC
#==============================================================================
            timestampSys = round(time.time() * 1000)
            result2 = self.client.read_holding_registers(timestampPFCRegister, 4)
            decoder = BinaryPayloadDecoder.fromRegisters(result2.registers, endian=Endian.Little)
            timestampPFC = decoder.decode_64bit_int()

#==============================================================================
#       Reads the values from modbus registers clamp by clamp
#       and buffers the results in  meterreadings{}
#		It is not possible to read all registers in one request because of the limitation of the Modbus-Message size to 255kb
# 		When the results of all clamps are buffered, they are published
#==============================================================================
            for x in range(0, len(self.clamps)):
                result = self.client.read_holding_registers(address, numberOfRegPerClamp)

                decoder = BinaryPayloadDecoder.fromRegisters(result.registers, endian=Endian.Little)
                decoded = {
                    'I1': decoder.decode_32bit_float(),
                    'I2': decoder.decode_32bit_float(),
                    'I3': decoder.decode_32bit_float(),
                    'U1': decoder.decode_32bit_float(),
                    'U2': decoder.decode_32bit_float(),
                    'U3': decoder.decode_32bit_float(),
                    'P1': decoder.decode_32bit_float(),
                    'P2': decoder.decode_32bit_float(),
                    'P3': decoder.decode_32bit_float(),
                    'Q1': decoder.decode_32bit_float(),
                    'Q2': decoder.decode_32bit_float(),
                    'Q3': decoder.decode_32bit_float(),
                    'S1': decoder.decode_32bit_float(),
                    'S2': decoder.decode_32bit_float(),
                    'S3': decoder.decode_32bit_float(),
                    'CosPhi1': decoder.decode_32bit_float(),
                    'CosPhi2': decoder.decode_32bit_float(),
                    'CosPhi3': decoder.decode_32bit_float(),
                    'PF1': decoder.decode_32bit_float(),
                    'PF2': decoder.decode_32bit_float(),
                    'PF3': decoder.decode_32bit_float(),
                    'Qua1': decoder.decode_32bit_float(),
                    'Qua2': decoder.decode_32bit_float(),
                    'Qua3': decoder.decode_32bit_float(),
                    'AEI1': decoder.decode_32bit_float(),
                    'AED1': decoder.decode_32bit_float(),
                    'REI1': decoder.decode_32bit_float(),
                    'REC1': decoder.decode_32bit_float(),
                    'AEI2': decoder.decode_32bit_float(),
                    'AED2': decoder.decode_32bit_float(),
                    'REI2': decoder.decode_32bit_float(),
                    'REC2': decoder.decode_32bit_float(),
                    'AEI3': decoder.decode_32bit_float(),
                    'AED3': decoder.decode_32bit_float(),
                    'REI3': decoder.decode_32bit_float(),
                    'REC3': decoder.decode_32bit_float(),
                    'DataValid' : decoder.decode_32bit_float()}
#==============================================================================
#        standardize both TimestampPFC and TimestampSYS precision to be millisecond
#==============================================================================
                decoded['TimestampPFC'] = str(timestampPFC)[0:13]
                decoded['TimestampSYS'] = timestampSys

#==============================================================================
#                 PFC measures energy values in mWh --> convert to watt-seconds
#==============================================================================
                decoded['AEI1'] = float(decoded['AEI1']) * 3.6
                decoded['AED1'] = float(decoded['AED1']) * 3.6
                decoded['REI1'] = float(decoded['REI1']) * 3.6
                decoded['REC1'] = float(decoded['REC1']) * 3.6
                decoded['AEI2'] = float(decoded['AEI2']) * 3.6
                decoded['AED2'] = float(decoded['AED2']) * 3.6
                decoded['REI2'] = float(decoded['REI2']) * 3.6
                decoded['REC2'] = float(decoded['REC2']) * 3.6
                decoded['AEI3'] = float(decoded['AEI3']) * 3.6
                decoded['AED3'] = float(decoded['AED3']) * 3.6
                decoded['REI3'] = float(decoded['REI3']) * 3.6
                decoded['REC3'] = float(decoded['REC3']) * 3.6

                meterreadingsV2[self.clampsV2[x]] = decoded
                meterreadings[self.clamps[x]] = decoded
                address += numberOfRegPerClamp

            self.publish(u'eshl.wago.v1.readout.wiz.494', json.dumps(meterreadings, sort_keys=True))
            self.publish(u'eshl.wago.v2.readout.wiz.494', meterreadingsV2)

#==============================================================================
#      If there is no connection to the pfc-modbus slave or no connection to the pfc at all
#      the blankDataSet is published
#==============================================================================
        except ConnectionException as connErr:
            for x in range(0, len(self.clamps)):
                    meterreadings[self.clamps[x]] = self.blankDataSetGen()
            self.publish(u'eshl.wago.v1.readout.wiz.494', json.dumps(meterreadings, sort_keys=True))
            self.publish(u'eshl.wago.v2.readout.wiz.494', meterreadings)
            sys.__stdout__.write('ConnectionException in-wago-wiz-494' + '\n' + 'Timestamp: ' + str(timestampSys) + ', Errorcode --> ' + str(connErr))
            sys.__stdout__.flush()
        except Exception as err:
            sys.__stdout__.write('Exception in-wago-wiz-494' + '\n' + 'Timestamp: ' + str(timestampSys) + ', Errorcode --> ' + str(err))
            sys.__stdout__.flush()
Example #30
0
def _defloat(registers):
    d = BinaryPayloadDecoder.fromRegisters(registers, byteorder='>')
    return [d.decode_32bit_float() for r in range(0, len(registers) // 2)]
Example #31
0
def run_binary_payload_ex():
    # ----------------------------------------------------------------------- #
    # We are going to use a simple client to send our requests
    # ----------------------------------------------------------------------- #
    client = ModbusClient('127.0.0.1', port=5020)
    client.connect()

    # ----------------------------------------------------------------------- #
    # If you need to build a complex message to send, you can use the payload
    # builder to simplify the packing logic.
    #
    # Here we demonstrate packing a random payload layout, unpacked it looks
    # like the following:
    #
    # - a 8 byte string 'abcdefgh'
    # - a 32 bit float 22.34
    # - a 16 bit unsigned int 0x1234
    # - another 16 bit unsigned int 0x5678
    # - an 8 bit int 0x12
    # - an 8 bit bitstring [0,1,0,1,1,0,1,0]
    # - an 32 bit uint 0x12345678
    # - an 32 bit signed int -0x1234
    # - an 64 bit signed int 0x12345678

    # The packing can also be applied to the word (wordorder) and bytes in each
    # word (byteorder)

    # The wordorder is applicable only for 32 and 64 bit values
    # Lets say we need to write a value 0x12345678 to a 32 bit register

    # The following combinations could be used to write the register

    # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #
    # Word Order - Big                      Byte Order - Big
    # word1 =0x1234 word2 = 0x5678

    # Word Order - Big                      Byte Order - Little
    # word1 =0x3412 word2 = 0x7856

    # Word Order - Little                   Byte Order - Big
    # word1 = 0x5678 word2 = 0x1234

    # Word Order - Little                   Byte Order - Little
    # word1 =0x7856 word2 = 0x3412
    # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #

    # ----------------------------------------------------------------------- #
    builder = BinaryPayloadBuilder(byteorder=Endian.Big,
                                   wordorder=Endian.Little)
    builder.add_string('abcdefgh')
    builder.add_bits([0, 1, 0, 1, 1, 0, 1, 0])
    builder.add_8bit_int(-0x12)
    builder.add_8bit_uint(0x12)
    builder.add_16bit_int(-0x5678)
    builder.add_16bit_uint(0x1234)
    builder.add_32bit_int(-0x1234)
    builder.add_32bit_uint(0x12345678)
    builder.add_16bit_float(12.34)
    builder.add_16bit_float(-12.34)
    builder.add_32bit_float(22.34)
    builder.add_32bit_float(-22.34)
    builder.add_64bit_int(-0xDEADBEEF)
    builder.add_64bit_uint(0x12345678DEADBEEF)
    builder.add_64bit_uint(0x12345678DEADBEEF)
    builder.add_64bit_float(123.45)
    builder.add_64bit_float(-123.45)
    payload = builder.to_registers()
    print("-" * 60)
    print("Writing Registers")
    print("-" * 60)
    print(payload)
    print("\n")
    payload = builder.build()
    address = 0
    # Can write registers
    # registers = builder.to_registers()
    # client.write_registers(address, registers, unit=1)

    # Or can write encoded binary string
    client.write_registers(address, payload, skip_encode=True, unit=1)
    # ----------------------------------------------------------------------- #
    # If you need to decode a collection of registers in a weird layout, the
    # payload decoder can help you as well.
    #
    # Here we demonstrate decoding a random register layout, unpacked it looks
    # like the following:
    #
    # - a 8 byte string 'abcdefgh'
    # - a 32 bit float 22.34
    # - a 16 bit unsigned int 0x1234
    # - another 16 bit unsigned int which we will ignore
    # - an 8 bit int 0x12
    # - an 8 bit bitstring [0,1,0,1,1,0,1,0]
    # ----------------------------------------------------------------------- #
    address = 0x0
    count = len(payload)
    result = client.read_holding_registers(address, count, unit=1)
    print("-" * 60)
    print("Registers")
    print("-" * 60)
    print(result.registers)
    print("\n")
    decoder = BinaryPayloadDecoder.fromRegisters(result.registers,
                                                 byteorder=Endian.Big,
                                                 wordorder=Endian.Little)

    assert decoder._byteorder == builder._byteorder, \
            "Make sure byteorder is consistent between BinaryPayloadBuilder and BinaryPayloadDecoder"

    assert decoder._wordorder == builder._wordorder, \
            "Make sure wordorder is consistent between BinaryPayloadBuilder and BinaryPayloadDecoder"

    decoded = OrderedDict([
        ('string', decoder.decode_string(8)),
        ('bits', decoder.decode_bits()),
        ('8int', decoder.decode_8bit_int()),
        ('8uint', decoder.decode_8bit_uint()),
        ('16int', decoder.decode_16bit_int()),
        ('16uint', decoder.decode_16bit_uint()),
        ('32int', decoder.decode_32bit_int()),
        ('32uint', decoder.decode_32bit_uint()),
        ('16float', decoder.decode_16bit_float()),
        ('16float2', decoder.decode_16bit_float()),
        ('32float', decoder.decode_32bit_float()),
        ('32float2', decoder.decode_32bit_float()),
        ('64int', decoder.decode_64bit_int()),
        ('64uint', decoder.decode_64bit_uint()),
        ('ignore', decoder.skip_bytes(8)),
        ('64float', decoder.decode_64bit_float()),
        ('64float2', decoder.decode_64bit_float()),
    ])

    print("-" * 60)
    print("Decoded Data")
    print("-" * 60)
    for name, value in iteritems(decoded):
        print("%s\t" % name, hex(value) if isinstance(value, int) else value)

    # ----------------------------------------------------------------------- #
    # close the client
    # ----------------------------------------------------------------------- #
    client.close()
Example #32
0
    def convert(self, config, data):
        self.__result["telemetry"] = []
        self.__result["attributes"] = []
        for config_data in data:
            if self.__result.get(config_data) is None:
                self.__result[config_data] = []
            for tag in data[config_data]:
                log.debug(tag)
                data_sent = data[config_data][tag]["data_sent"]
                input_data = data[config_data][tag]["input_data"]
                log.debug("Called convert function from %s with args", self.__class__.__name__)
                log.debug(data_sent)
                log.debug(input_data)
                result = None
                if data_sent.get("functionCode") == 1 or data_sent.get("functionCode") == 2:
                    result = input_data.bits
                    log.debug(result)
                    if "registerCount" in data_sent:
                        result = result[:data_sent["registerCount"]]
                    else:
                        result = result[0]
                elif data_sent.get("functionCode") == 3 or data_sent.get("functionCode") == 4:
                    result = input_data.registers
                    byte_order = data_sent.get("byteOrder", "LITTLE")
                    reg_count = data_sent.get("registerCount", 1)
                    type_of_data = data_sent["type"]
                    try:
                        try:
                            if byte_order == "LITTLE":
                                decoder = BinaryPayloadDecoder.fromRegisters(result, byteorder=Endian.Little)
                            elif byte_order == "BIG":
                                decoder = BinaryPayloadDecoder.fromRegisters(result, byteorder=Endian.Big)
                        except TypeError:
                            if byte_order == "LITTLE":
                                decoder = BinaryPayloadDecoder.fromRegisters(result, endian=Endian.Little)
                            elif byte_order == "BIG":
                                decoder = BinaryPayloadDecoder.fromRegisters(result, endian=Endian.Big)
                        else:
                            log.warning("byte order is not BIG or LITTLE")
                            # continue
                    except Exception as e:
                        log.error(e)
                    if type_of_data == "string":
                        result = decoder.decode_string(2 * reg_count)
                    elif type_of_data == "long":
                        try:
                            if reg_count == 1:
                                # r = decoder.decode_8bit_int()
                                result = decoder.decode_16bit_int()
                            elif reg_count == 2:
                                result = decoder.decode_32bit_int()
                            elif reg_count == 4:
                                result = decoder.decode_64bit_int()
                            else:
                                log.warning("unsupported register count for long data type in response for tag %s",
                                            data_sent["tag"])
                        except Exception as e:
                            log.exception(e)
                    elif type_of_data == "double":
                        if reg_count == 2:
                            result = decoder.decode_32bit_float()
                        elif reg_count == 4:
                            result = decoder.decode_64bit_float()
                        else:
                            log.warning("unsupported register count for double data type in response for tag %s",
                                        data_sent["tag"])
                            # continue
                    elif type_of_data == "bit":
                        if "bit" in data_sent:
                            if type(result) == list:
                                if len(result) > 1:
                                    log.warning("with bit parameter only one register is expected, got more then one in response for tag %s",
                                                data_sent["tag"])
                                    continue
                                result = result[0]
                            position = 15 - data_sent["bit"]  # reverse order
                            # transform result to string representation of a bit sequence, add "0" to make it longer >16
                            result = "0000000000000000" + str(bin(result)[2:])
                            # get length of 16, then get bit, then cast it to int(0||1 from "0"||"1", then cast to boolean)
                            result = bool(int((result[len(result) - 16:])[15 - position]))
                        else:
                            log.error("Bit address not found in config for modbus connector for tag: %s", data_sent["tag"])

                    else:
                        log.warning("unknown data type, not string, long or double in response for tag %s",
                                    data_sent["tag"])
                        continue
                try:
                    if result == 0:
                        self.__result[config_data].append({tag: result})
                    elif int(result):
                        self.__result[config_data].append({tag: result})
                except ValueError:
                    try:
                        self.__result[config_data].append({tag: int(result, 16)})
                    except ValueError:
                        self.__result[config_data].append({tag: result.decode('UFT-8')})
        self.__result["telemetry"] = self.__result.pop("timeseries")
        log.debug(self.__result)
        return self.__result
Example #33
0
def get_pv_data(config):

    host = config.get('inv_host')
    port = config.get('inv_port', 502)
    modbusid = config.get('inv_modbus', 3)
    manufacturer = config.get('inv_modbus', 'Default')
    registers = eval(config.get('registers'))
    client = ModbusClient(host=host, port=port)
    try:
        client.connect()
    except:
        print('Modbus Connection Error', 'could not connect to target. Check your settings, please.')
        return None




    data = {}  ## empty data store for current values

    for myreg in registers:
        ## if the connection is somehow not possible (e.g. target not responding)
        #  show a error message instead of excepting and stopping
        try:
            received = client.read_input_registers(address=int(myreg[0]),
                                                        count=modbusdatatype[myreg[1]],
                                                        unit=modbusid)
        except:
            thisdate = str(datetime.datetime.now()).partition('.')[0]
            thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.'
            print(thiserrormessage)
            return  None ## prevent further execution of this function

        name = myreg[3]
        message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big)
        ## provide the correct result depending on the defined datatype
        if myreg[1] == 'S32':
            interpreted = message.decode_32bit_int()
        elif myreg[1] == 'U32':
            interpreted = message.decode_32bit_uint()
        elif myreg[1] == 'U64':
            interpreted = message.decode_64bit_uint()
        elif myreg[1] == 'STR32':
            interpreted = message.decode_string(32)
        elif myreg[1] == 'S16':
            interpreted = message.decode_16bit_int()
        elif myreg[1] == 'U16':
            interpreted = message.decode_16bit_uint()
        else:  ## if no data type is defined do raw interpretation of the delivered data
            interpreted = message.decode_16bit_uint()

        ## check for "None" data before doing anything else
        if ((interpreted == MIN_SIGNED) or (interpreted == MAX_UNSIGNED)):
            value = None
        else:
        ## put the data with correct formatting into the data table
            if myreg[2] == 'FIX3':
                value = float(interpreted) / 1000
            elif myreg[2] == 'FIX2':
                value = float(interpreted) / 100
            elif myreg[2] == 'FIX1':
                value = float(interpreted) / 10
            elif myreg[2] == 'UTF8':
                value = str(interpreted,'UTF-8').rstrip("\x00")
            elif myreg[2] == 'ENUM':
                e=pvenums.get(name,{})
                value = e.get(interpreted,str(interpreted))
            else:
                value = interpreted
        data[name] = value

    client.close()
    return data
def check_values(p_client,p_first_register, m_client, m_first_register,sleep_time):
    global BAR_INPUT, CUMULATIVE_VOLUME
    exp_item = OrderedDict()
    log.debug("check_values %s %s" % (p_client,m_client))
    # m_start_address = m_first_register-1  # if zero_mode=False => inizia a leggere da Manifold a partire da m_first_register-1 per gli N successivi,escluso m_start_address
    #################################### CAVALLETTO
    m_start_address = m_first_register
    m_rr = m_client.read_holding_registers(m_start_address,35)
    # Machine ID
    m_ID = m_rr.registers[1-1]
    # IP ADDR. da 32,33,34 e 35
    sIPAddr = "%d.%d.%d.%d" %  tuple(m_rr.registers[32-1:36-1])
    # pressione in mA in posizione 4
    p_mA = m_rr.registers[4-1]
    p_bar = scale(p_p1,p_p2,p_mA)
    # portata in mA in posizione 6
    q_mA = m_rr.registers[6-1]
    q_bar = scale(q_p1,q_p2,q_mA)
    CUMULATIVE_VOLUME += q_bar*(sleep_time/60.)
    p_eff, static_head, p_hdlf = peff(p_bar, q_bar)
    log.debug("\n#### Readings from %s (%s)####\n##Pressure \tP(mA)=%d \tP(bar)=%d \n##Flow-rate \tQ(mA)=%d \tQ(lit/min)=%d Peff = %f\n####" %(m_ID, sIPAddr,m_rr.registers[4-1], p_bar, m_rr.registers[6-1],q_bar, p_eff ))
    exp_item["TIME"] = datetime.datetime.utcnow().strftime("%Y%m%d %H:%M:%S.%f")
    exp_item["m_ID"] = m_ID
    exp_item["m_IP"] = sIPAddr
    exp_item["STAGE_LENGTH"] = STAGE_LENGTH
    exp_item["p_gauge"] = p_bar
    exp_item["static_head"] = static_head
    exp_item["p_hdlf"] = p_hdlf
    exp_item["p_eff"] = p_eff
    exp_item["R"] = R
    exp_item["q_bar"] = q_bar
    exp_item["q_cum"] = CUMULATIVE_VOLUME
    volume_m = CUMULATIVE_VOLUME/STAGE_LENGTH
    exp_item["volume_m"] = volume_m
    BAR_INPUT = q_bar
    #################################### INIETTORE
    #p_start_address = p_first_register-1 # if zero_mode=False => inizia a leggere da m_first_register-1 e prendi gli N successivi,escluso m_start_address
    p_start_address = p_first_register
    p_rr = p_client.read_holding_registers(p_start_address+500,100,unit=1) # danzi.tn@20160729 iniettore inizia da 0 noi prendiamo da 500 a 599
    p_out = p_rr.registers[16] # pressione in uscita dall'iniettore
    q_out = p_rr.registers[20] # portata in uscita dall'iniettore
    p_max = p_rr.registers[60] # pressione massima iniettore
    q_max = p_rr.registers[62] # portata massima iniettore
    np_max = R + p_out - p_eff
    dP_pump = p_max - p_out
    dP_borehole = R - p_eff
    decoder = BinaryPayloadDecoder.fromRegisters(p_rr.registers[22:26],endian=Endian.Little)
    f_522 = decoder.decode_32bit_float()
    f_524 = decoder.decode_32bit_float()
    log.debug("\n#### Readings ####\n##p_bar=%f;p_eff=%f;p_out=%d;p_max=%d;np_max=%d;q=%f;V=%f\n####" %(p_bar, p_eff, p_out,p_max,np_max,q_bar,CUMULATIVE_VOLUME))
    bR, bStop, next_mix_type, bIntermittent = check_mix(volume_m, MIX_TYPE, p_eff,R,BUPSTAGE, P_PREVIOUS )
    #check_mix(volume_m,p_eff,R)
    exp_item["stop"] = bStop
    exp_item["ok R"] = bR
    exp_item["next mix_type"] = next_mix_type
    exp_item["p_out"] = p_out
    exp_item["q_out"] = q_out # salvo anche portata in uscita dall'iniettore
    exp_item["q_max"] = q_max # salvo anche portata massima dell'iniettore
    exp_item["p_max"] = p_max
    exp_item["p_max_new"] = np_max
    exp_item["dP_pump"] = dP_pump
    exp_item["dP_borehole"] = dP_borehole
    return exp_item
Example #35
0
class ModbusSerialReader(BaseReader):
    """"
    A class to manage Mobus serial connections.

    Constants:

        KEYS (dict[string]):
            Defines the dictionary keys of a Modbus request.

        __TYPES (List[string]):
            A list of all data types that can be read.

        __REGISTER_COUNT_BY_TYPE (dict[int]):
            Defines the mapping of input type to registry size.

        __DECODER_BY_TYPE (dict[lambda]):
            Defines the mapping of decoding functions.

    Attributes:

        client (pymodbus.client.sync.ModbusSerialClient):
            Object of the ModbusSerialClient class.

    """
    # Defining the dictionary keys of a Modbus request
    KEYS = {
        'NAME': 'name',
        'SLAVE_UNIT': 'slave_unit',
        'ADDRESS': 'address',
        'TYPE': 'type',
    }

    # Defining types codes
    __TYPES = ['UInt16', 'Int16', 'UInt32', 'Int64', 'UTF8', 'Float32']

    # Defining the mapping of input type to registry size
    __REGISTER_COUNT_BY_TYPE = {
        'UInt16': 1,
        'Int16': 1,
        'UInt32': 2,
        'Int64': 4,
        'UTF8': 8,
        'Float32': 2,
    }

    # Defining the mapping of decoding functions
    __DECODER_BY_TYPE = {
        'UInt16': lambda x: BinaryPayloadDecoder.fromRegisters(x, endian=Endian.Big).decode_16bit_uint(),
        'Int16': lambda x: BinaryPayloadDecoder.fromRegisters(x, endian=Endian.Big).decode_16bit_int(),
        'UInt32': lambda x: BinaryPayloadDecoder.fromRegisters(x, endian=Endian.Big).decode_32bit_uint(),
        'Int64': lambda x: BinaryPayloadDecoder.fromRegisters(x, endian=Endian.Big).decode_64bit_int(),
        'UTF8': lambda x: BinaryPayloadDecoder.fromRegisters(x, endian=Endian.Big).decode_string(8),
        'Float32': lambda x: BinaryPayloadDecoder.fromRegisters(x, endian=Endian.Big).decode_32bit_float(),
    }

    client = None

    def __init__(self, port, parity, baudrate, timeout=0.05,
                 sensor_name='sensor', sensor_location='location',
                 dropbox_keys=None, database_keys=None, delimiter=',',
                 output_file_ext='.csv', output_file_folder='Outputs'):
        """
        Constructor method of the ModbusSerialReader class.
        The Modbus client is initialized.

        Parameters:

            Argument 1: port (string)
                The address of the port that is connected to the device.

            Argument 2: parity (string)
                The parity setting of the connection.

            Argument 3: baudrate (int)
                The rate of bits transfer per second.

            Argument 4: timeout (float, optional)
                The amount of time given for the client to read per request.
                Defaults to 0.05.

            Argument 5, 6, 7, 8, 9, 10, 11: See BaseReader

        """
        super(ModbusSerialReader, self).__init__(sensor_name=sensor_name,
                                                 sensor_location=sensor_location,
                                                 dropbox_keys=dropbox_keys,
                                                 database_keys=database_keys,
                                                 delimiter=delimiter,
                                                 output_file_ext=output_file_ext,
                                                 output_file_folder=output_file_folder)
        self.initialize_connection(port, parity, baudrate, timeout)

    def initialize_connection(self, port, parity, baudrate, timeout):
        """
        Defines and set the class attribute for the Modbus serial client with
        the settings given in the parameters.

        Parameters:

            Argument 1: port (string)
                The address of the port that is connected to the device.

            Argument 2: parity (string)
                The parity setting of the connection.
                Must either be one of "E", "O" or "N" only.

            Argument 3: baudrate (int)
                The rate of bits transfer per second.
                Must be in the possible values of 300-100000.

        Raises:

            ValueError: If parity code is invalid, or baudrate is invalid; < 300 or > 1000000.

            SystemError: If connection with the device fails.

        """
        # Validation
        if parity not in 'EON' or len(parity) != 1:
            raise ValueError('Invalid parity code; enter either "E", "O" or "N"')
        if baudrate < 300 or baudrate > 100000:
            raise ValueError('Invalid baudrate; enter possible values of 300-100000')

        self.client = ModbusSerialClient(
            method='rtu',
            port=port,
            stopbits=1,
            bytesize=8,
            parity=parity,
            baudrate=baudrate,
            timeout=timeout
        )
        if not self.test_connection():
            raise SystemError('Connection with device failed; retry connection using initialize_connection()')

    def test_connection(self):
        """
        Checks and reports the status of the serial Modbus connection.

        Returns:
            True: If the connection is valid;
            False: If the connection is not valid.

        Raises:
            SystemError: If the Modbus client is yet to be initialized.

        """
        if self.client is None:
            raise SystemError('Modbus client not yet initialize; run initialize_connection() first')
        return self.client.connect()

    def read_input(self, input_filename, has_headers=True, delimiter=','):
        """
        Reads a list of input settings from a file in the local directory.

        Parameters:

            Argument 1: input_filename (string)
                The name of the input file to be read.

            Argument 2: has_headers (bool, optional)
                True if input file has headers; false otherwise.
                Defaults to True.

            Argument 3: delimiter (string, optional)
                A separator sequence to denote end of data read.
                Defaults to "," (comma).

        Note:

            The required format of the input file is:

                [Name of data] [Slave unit], [Starting register address], [Data type]

        Returns:

            List of dictionary (List[dict]):
                List of requests represented in dictionary form.
                e.g.  [ { 'name': 'apparent_power', 'slave_unit': '1', 'address': '3053', 'type': 'Float32' },
                        { 'name': 'real_power', 'slave_unit': '1', 'address': '3053', 'type': 'Float32' },
                        { 'name': 'total_power', 'slave_unit': '1', 'address': '3053', 'type': 'Float32' } ]

        Raises:

            SystemError: If the input fie does not exist.

            TypeError: If type code is invalid.

            ValueError: If address is invalid range; < 0, or > 39999 or
                                slave_unit, address is not an integer.

        """
        # Validation
        if not isfile(input_filename):
            raise SystemError('Input file "' + input_filename + '" does not exist')

        # Reads in the data
        with open(input_filename, 'rb') as input_file:  # rb: read-only in binary
            header = [self.KEYS['NAME'], self.KEYS['SLAVE_UNIT'], self.KEYS['ADDRESS'], self.KEYS['TYPE']]
            if has_headers:
                output = [dict(zip(header, line.strip().split(delimiter))) for line in input_file][1:]  # remove first row
            else:
                output = [dict(zip(header, line.strip().split(delimiter))) for line in input_file]

        # To convert types and data validation
        for request in output:
            request[self.KEYS['SLAVE_UNIT']] = int(request[self.KEYS['SLAVE_UNIT']])  # for slave unit
            request[self.KEYS['ADDRESS']] = int(request[self.KEYS['ADDRESS']])  # for address
            if request[self.KEYS['ADDRESS']] < 0 or request[self.KEYS['ADDRESS']] > 39999:
                raise ValueError('Address "' + str(request[self.KEYS['ADDRESS']]) + '" not within possible range: 0-39999')
            if request[self.KEYS['TYPE']] not in self.__TYPES:  # for type
                raise TypeError('Type code "' + request[self.KEYS['TYPE']] + '" entered is invalid')
        return output

    def execute_request(self, request):
        """
        Executes a reading request.

        Parameters:

            Argument 1: request (dict)
                The request represented by a dictionary as prepared by the input reader.

        Returns:

            Reading (type: any):
                The decoded data parsed in the data type of the format as given.

        Raises:

            KeyError: If any of the keys of the dictionary is invalid.

            SystemError: If the connection of the Modbus client is invalid.

        """
        # Validation
        if not self.test_connection():
            raise SystemError('Connection with device failed; retry connection using initialize_connection()')

        # Read raw values from holding registers
        response = self.client.read_holding_registers(
            address=request[self.KEYS['ADDRESS']],
            count=self.__REGISTER_COUNT_BY_TYPE[request[self.KEYS['TYPE']]],
            unit=request[self.KEYS['SLAVE_UNIT']]
        )

        return self.decode(response, request[self.KEYS['TYPE']])

    def decode(self, response, data_type):
        """
        Decodes the response according to the data format given.

        Parameters:

            Argument 1: response (List[int])
                The response of the read represented by a list of 16-bit int values in a list.

            Argument 2: data_type (string)
                The format of the data to be decoded.

        Returns:

            Reading (type: any):
                The decoded data parsed in the data type of the format as given.

        Raises:

            ValueEror: If the output is invalid.

        """
        try:
            return self.__DECODER_BY_TYPE[data_type](response.registers)
        except:
            raise ValueError('Invalid output decoded')
Example #36
0
def updating_pump_writer(a):
    ''' A worker process that runs every so often and
    updates live values of the context. It should be noted
    that there is a race condition for the update.

    :param arguments: The input arguments to the call
    '''
    context  = a[0]
    srv_id = a[1]
    handler = a[2]
    register = 3
    slave_id = 0x00
   
    values   = context[slave_id].getValues(register, 0, count=600)
    # update P and Q with random values
    logInfo.debug("PUMP context values: " + str(values))

    logInfo.debug("PUMP p_out=%d; q_out=%d" % (handler.p_out,handler.q_out))

    decoder = BinaryPayloadDecoder.fromRegisters(values[502:503],endian=Endian.Little)
    bits_502 = decoder.decode_bits()
    bits_502 += decoder.decode_bits()
    decoder = BinaryPayloadDecoder.fromRegisters(values[552:553],endian=Endian.Little)
    bits_552 = decoder.decode_bits()
    bits_552 += decoder.decode_bits()
    decoder = BinaryPayloadDecoder.fromRegisters(values[506:507],endian=Endian.Little)
    bits_506 = decoder.decode_bits()
    bits_506 += decoder.decode_bits()

    cicli_min = 0
    p_new = 0
    q_val = 0
    # if iniettore Started
    if handler.pumpStarted and not bits_502[7]:    
        handler.pumpStarted = False
    
    if bits_502[7]:
        #cicli_min = cicli_rand.rvs()
        q_val = handler.q_out
        if q_val < 0:
            q_val = 0
        cicli_min = int(q_val / liters_cycle )
        p_new = handler.p_out
   

    logInfo.debug("PUMP p_new=%d" % p_new)
    
    q_m_ch = 60.0*q_val/1000.0
    handler.cicli_min = cicli_min
    handler.q_m_ch = q_m_ch
    logInfo.debug("PUMP cicli=%d, q=%f, mc=%f" % (cicli_min, q_val,q_m_ch))
    # conversione float - Endian.Little il primo è il meno significativo
    handler.p_pump_out = p_new
    handler.q_pump_out = cicli_min
    values[516] = p_new # %MW516 PRESSIONE ATTUALE
    values[520] = cicli_min
    
    handler.qmax = values[562]
    handler.pmax = values[560]
    builder = BinaryPayloadBuilder(endian=Endian.Little)
    builder.add_32bit_float(q_val)
    builder.add_32bit_float(q_m_ch)
    reg=builder.to_registers()
    logInfo.debug("PUMP 2 x 32bit_float = %s" % str(reg))
    values[522:526]=reg

    logInfo.debug("PUMP On Pump Server %02d new values (516-525): %s" % (srv_id, str(values[516:526])))

    # assign new values to context
    values[599] = 699
    context[slave_id].setValues(register, 0, values)
async def write_to_influx(dbhost, dbport, mbmeters, period, dbname,
                          legacysupport):
    global client
    global datapoint
    global reg_block
    global promInv
    global promMeter

    def trunc_float(floatval):
        return float('%.2f' % floatval)

    try:
        solar_client = InfluxDBClient(host=dbhost, port=dbport, db=dbname)
        await solar_client.create_database(db=dbname)
    except ClientConnectionError as e:
        logger.error(f'Error during connection to InfluxDb {dbhost}: {e}')
        return
    logger.info('Database opened and initialized')

    # Connect to the solaredge inverter
    client = ModbusClient(args.inverter_ip,
                          port=args.inverter_port,
                          unit_id=args.unitid,
                          auto_open=True)

    # Read the common blocks on the Inverter
    while True:
        reg_block = {}
        reg_block = client.read_holding_registers(40004, 65)
        if reg_block:
            decoder = BinaryPayloadDecoder.fromRegisters(reg_block,
                                                         byteorder=Endian.Big,
                                                         wordorder=Endian.Big)
            InvManufacturer = decoder.decode_string(32).decode(
                'UTF-8')  #decoder.decode_32bit_float(),
            InvModel = decoder.decode_string(32).decode(
                'UTF-8')  #decoder.decode_32bit_int(),
            Invfoo = decoder.decode_string(16).decode('UTF-8')
            InvVersion = decoder.decode_string(16).decode(
                'UTF-8')  #decoder.decode_bits()
            InvSerialNumber = decoder.decode_string(32).decode('UTF-8')
            InvDeviceAddress = decoder.decode_16bit_uint()

            print('*' * 60)
            print('* Inverter Info')
            print('*' * 60)
            print(' Manufacturer: ' + InvManufacturer)
            print(' Model: ' + InvModel)
            print(' Version: ' + InvVersion)
            print(' Serial Number: ' + InvSerialNumber)
            print(' ModBus ID: ' + str(InvDeviceAddress))
            break
        else:
            # Error during data receive
            if client.last_error() == 2:
                logger.error(
                    f'Failed to connect to SolarEdge inverter {client.host()}!'
                )
            elif client.last_error() == 3 or client.last_error() == 4:
                logger.error('Send or receive error!')
            elif client.last_error() == 5:
                logger.error('Timeout during send or receive operation!')
            await asyncio.sleep(period)

    # Read the common blocks on the meter/s (if present)
    connflag = False
    if mbmeters >= 1:
        while True:
            dictMeterLabel = []
            for x in range(1, mbmeters + 1):
                reg_block = {}
                if x == 1:
                    reg_block = client.read_holding_registers(40123, 65)
                if x == 2:
                    reg_block = client.read_holding_registers(40297, 65)
                if x == 3:
                    reg_block = client.read_holding_registers(40471, 65)
                if reg_block:
                    decoder = BinaryPayloadDecoder.fromRegisters(
                        reg_block, byteorder=Endian.Big, wordorder=Endian.Big)
                    MManufacturer = decoder.decode_string(32).decode(
                        'UTF-8')  #decoder.decode_32bit_float(),
                    MModel = decoder.decode_string(32).decode(
                        'UTF-8')  #decoder.decode_32bit_int(),
                    MOption = decoder.decode_string(16).decode('UTF-8')
                    MVersion = decoder.decode_string(16).decode(
                        'UTF-8')  #decoder.decode_bits()
                    MSerialNumber = decoder.decode_string(32).decode('UTF-8')
                    MDeviceAddress = decoder.decode_16bit_uint()
                    fooLabel = MManufacturer.split(
                        '\x00')[0] + '(' + MSerialNumber.split('\x00')[0] + ')'
                    dictMeterLabel.append(fooLabel)
                    print('*' * 60)
                    print('* Meter ' + str(x) + ' Info')
                    print('*' * 60)
                    print(' Manufacturer: ' + MManufacturer)
                    print(' Model: ' + MModel)
                    print(' Mode: ' + MOption)
                    print(' Version: ' + MVersion)
                    print(' Serial Number: ' + MSerialNumber)
                    print(' ModBus ID: ' + str(MDeviceAddress))
                    if x == mbmeters:
                        print('*' * 60)
                    connflag = True
                else:
                    # Error during data receive
                    if client.last_error() == 2:
                        logger.error(
                            f'Failed to connect to SolarEdge inverter {client.host()}!'
                        )
                    elif client.last_error() == 3 or client.last_error() == 4:
                        logger.error('Send or receive error!')
                    elif client.last_error() == 5:
                        logger.error(
                            'Timeout during send or receive operation!')
                    await asyncio.sleep(period)
            if connflag:
                break

    # Start the loop for collecting the metrics...
    while True:
        try:
            reg_block = {}
            dictInv = {}
            reg_block = client.read_holding_registers(40069, 50)
            if reg_block:
                # print(reg_block)
                # reg_block[0] = Sun Spec DID
                # reg_block[1] = Length of Model Block
                # reg_block[2] = AC Total current value
                # reg_block[3] = AC Phase A current value
                # reg_block[4] = AC Phase B current value
                # reg_block[5] = AC Phase C current value
                # reg_block[6] = AC current scale factor
                # reg_block[7] = AC Phase A to B voltage value
                # reg_block[8] = AC Phase B to C voltage value
                # reg_block[9] = AC Phase C to A voltage value
                # reg_block[10] = AC Phase A to N voltage value
                # reg_block[11] = AC Phase B to N voltage value
                # reg_block[12] = AC Phase C to N voltage value
                # reg_block[13] = AC voltage scale factor
                # reg_block[14] = AC Power value
                # reg_block[15] = AC Power scale factor
                # reg_block[16] = AC Frequency value
                # reg_block[17] = AC Frequency scale factor
                # reg_block[18] = AC Apparent Power
                # reg_block[19] = AC Apparent Power scale factor
                # reg_block[20] = AC Reactive Power
                # reg_block[21] = AC Reactive Power scale factor
                # reg_block[22] = AC Power Factor
                # reg_block[23] = AC Power Factor scale factor
                # reg_block[24] = AC Lifetime Energy (HI bits)
                # reg_block[25] = AC Lifetime Energy (LO bits)
                # reg_block[26] = AC Lifetime Energy scale factor
                # reg_block[27] = DC Current value
                # reg_block[28] = DC Current scale factor
                # reg_block[29] = DC Voltage value
                # reg_block[30] = DC Voltage scale factor
                # reg_block[31] = DC Power value
                # reg_block[32] = DC Power scale factor
                # reg_block[34] = Inverter temp
                # reg_block[37] = Inverter temp scale factor
                # reg_block[38] = Inverter Operating State
                # reg_block[39] = Inverter Status Code
                datapoint = {
                    'measurement': 'SolarEdge',
                    'tags': {},
                    'fields': {}
                }
                logger.debug(f'inverter reg_block: {str(reg_block)}')
                datapoint['tags']['inverter'] = str(1)

                data = BinaryPayloadDecoder.fromRegisters(reg_block,
                                                          byteorder=Endian.Big,
                                                          wordorder=Endian.Big)

                # SunSpec DID
                # Register 40069
                fooVal = trunc_float(data.decode_16bit_uint())
                fooName = 'SunSpec_DID'
                if fooVal < 65535:
                    dictInv[fooName] = fooVal
                else:
                    dictInv[fooName] = 0.0

                # SunSpec Length
                # Register 40070
                fooVal = trunc_float(data.decode_16bit_uint())
                fooName = 'SunSpec_Length'
                if fooVal < 65535:
                    dictInv[fooName] = fooVal
                else:
                    dictInv[fooName] = 0.0

                # AC Current
                data.skip_bytes(8)
                # Register 40075
                scalefactor = 10**data.decode_16bit_int()
                data.skip_bytes(-10)
                # Register 40071-40074
                fooVal = trunc_float(data.decode_16bit_uint())
                fooName = 'AC_Current'
                if fooVal < 65535:
                    dictInv[fooName] = fooVal * scalefactor
                else:
                    dictInv[fooName] = 0.0
                fooVal = trunc_float(data.decode_16bit_uint())
                fooName = 'AC_CurrentA'
                if fooVal < 65535:
                    dictInv[fooName] = fooVal * scalefactor
                else:
                    dictInv[fooName] = 0.0
                fooVal = trunc_float(data.decode_16bit_uint())
                fooName = 'AC_CurrentB'
                if fooVal < 65535:
                    dictInv[fooName] = fooVal * scalefactor
                else:
                    dictInv[fooName] = 0.0
                fooVal = trunc_float(data.decode_16bit_uint())
                fooName = 'AC_CurrentC'
                if fooVal < 65535:
                    dictInv[fooName] = fooVal * scalefactor
                else:
                    dictInv[fooName] = 0.0

                # AC Voltage
                data.skip_bytes(14)
                # Register 40082
                scalefactor = 10**data.decode_16bit_int()
                data.skip_bytes(-14)
                # Register 40077
                fooVal = trunc_float(data.decode_16bit_uint())
                fooName = 'AC_VoltageAB'
                if fooVal < 65535:
                    dictInv[fooName] = fooVal * scalefactor
                else:
                    dictInv[fooName] = 0.0
                fooVal = trunc_float(data.decode_16bit_uint())
                fooName = 'AC_VoltageBC'
                if fooVal < 65535:
                    dictInv[fooName] = fooVal * scalefactor
                else:
                    dictInv[fooName] = 0.0
                fooVal = trunc_float(data.decode_16bit_uint())
                fooName = 'AC_VoltageCA'
                if fooVal < 65535:
                    dictInv[fooName] = fooVal * scalefactor
                else:
                    dictInv[fooName] = 0.0
                fooVal = trunc_float(data.decode_16bit_uint())
                fooName = 'AC_VoltageAN'
                if fooVal < 65535:
                    dictInv[fooName] = fooVal * scalefactor
                else:
                    dictInv[fooName] = 0.0
                fooVal = trunc_float(data.decode_16bit_uint())
                fooName = 'AC_VoltageBN'
                if fooVal < 65535:
                    dictInv[fooName] = fooVal * scalefactor
                else:
                    dictInv[fooName] = 0.0
                fooVal = trunc_float(data.decode_16bit_uint())
                fooName = 'AC_VoltageCN'
                if fooVal < 65535:
                    dictInv[fooName] = fooVal * scalefactor
                else:
                    dictInv[fooName] = 0.0

                # AC Power
                data.skip_bytes(4)
                # Register 40084
                scalefactor = 10**data.decode_16bit_int()
                data.skip_bytes(-4)
                # Register 40083
                fooVal = trunc_float(data.decode_16bit_int())
                fooName = 'AC_Power'
                if fooVal < 65535:
                    dictInv[fooName] = fooVal * scalefactor
                else:
                    dictInv[fooName] = 0.0

            # AC Frequency
                data.skip_bytes(4)
                # Register 40086
                scalefactor = 10**data.decode_16bit_int()
                data.skip_bytes(-4)
                # Register 40085
                fooVal = trunc_float(data.decode_16bit_uint())
                fooName = 'AC_Frequency'
                if fooVal < 65535:
                    dictInv[fooName] = fooVal * scalefactor
                else:
                    dictInv[fooName] = 0.0

                # AC Apparent Power
                data.skip_bytes(4)
                # Register 40088
                scalefactor = 10**data.decode_16bit_int()
                data.skip_bytes(-4)
                # Register 40087
                fooVal = trunc_float(data.decode_16bit_int())
                fooName = 'AC_VA'
                if fooVal < 65535:
                    dictInv[fooName] = fooVal * scalefactor
                else:
                    dictInv[fooName] = 0.0

                # AC Reactive Power
                data.skip_bytes(4)
                # Register 40090
                scalefactor = 10**data.decode_16bit_int()
                data.skip_bytes(-4)
                # Register 40089
                fooVal = trunc_float(data.decode_16bit_int())
                fooName = 'AC_VAR'
                if fooVal < 65535:
                    dictInv[fooName] = fooVal * scalefactor
                else:
                    dictInv[fooName] = 0.0

                # AC Power Factor
                data.skip_bytes(4)
                # Register 40092
                scalefactor = 10**data.decode_16bit_int()
                data.skip_bytes(-4)
                # Register 40091
                fooVal = trunc_float(data.decode_16bit_int())
                fooName = 'AC_PF'
                if fooVal < 65535:
                    dictInv[fooName] = fooVal * scalefactor
                else:
                    dictInv[fooName] = 0.0

                # AC Lifetime Energy Production
                data.skip_bytes(6)
                # Register 40095
                scalefactor = 10**data.decode_16bit_uint()
                data.skip_bytes(-6)
                # Register 40093
                fooVal = trunc_float(data.decode_32bit_uint())
                fooName = 'AC_Energy_WH'
                if fooVal < 4294967295:
                    dictInv[fooName] = fooVal * scalefactor
                else:
                    dictInv[fooName] = 0.0

                # DC Current
                data.skip_bytes(4)
                # Register 40097
                scalefactor = 10**data.decode_16bit_int()
                data.skip_bytes(-4)
                # Register 40096
                fooVal = trunc_float(data.decode_16bit_uint())
                fooName = 'DC_Current'
                if fooVal < 65535:
                    dictInv[fooName] = fooVal * scalefactor
                else:
                    dictInv[fooName] = 0.0

                # DC Voltage
                data.skip_bytes(4)
                # Register 40099
                scalefactor = 10**data.decode_16bit_int()
                data.skip_bytes(-4)
                # Register 40098
                fooVal = trunc_float(data.decode_16bit_uint())
                fooName = 'DC_Voltage'
                if fooVal < 65535:
                    dictInv[fooName] = fooVal * scalefactor
                else:
                    dictInv[fooName] = 0.0

                # DC Power
                data.skip_bytes(4)
                # Register 40101
                scalefactor = 10**data.decode_16bit_int()
                data.skip_bytes(-4)
                # Register 40100
                fooVal = trunc_float(data.decode_16bit_int())
                fooName = 'DC_Power'
                if fooVal < 65535:
                    dictInv[fooName] = fooVal * scalefactor
                else:
                    dictInv[fooName] = 0.0

                # Inverter Temp
                data.skip_bytes(10)
                # Register 40106
                scalefactor = 10**data.decode_16bit_int()
                data.skip_bytes(-8)
                # Register 40103
                fooVal = trunc_float(data.decode_16bit_int())
                fooName = 'Temp_Sink'
                if fooVal < 65535:
                    dictInv[fooName] = fooVal * scalefactor
                else:
                    dictInv[fooName] = 0.0

                # Inverter Operating State
                data.skip_bytes(6)
                # Register 40107
                fooVal = trunc_float(data.decode_16bit_uint())
                fooName = 'Status'
                if fooVal < 65535:
                    dictInv[fooName] = fooVal
                else:
                    dictInv[fooName] = 0.0

                # Inverter Operating Status Code
                # Register 40108
                fooVal = trunc_float(data.decode_16bit_uint())
                fooName = 'Status_Vendor'
                if fooVal < 65535:
                    dictInv[fooName] = fooVal
                else:
                    dictInv[fooName] = 0.0

                # Adding the ScaleFactor elements
                dictInv['AC_Current_SF'] = 0.0
                dictInv['AC_Voltage_SF'] = 0.0
                dictInv['AC_Power_SF'] = 0.0
                dictInv['AC_Frequency_SF'] = 0.0
                dictInv['AC_VA_SF'] = 0.0
                dictInv['AC_VAR_SF'] = 0.0
                dictInv['AC_PF_SF'] = 0.0
                dictInv['AC_Energy_WH_SF'] = 0.0
                dictInv['DC_Current_SF'] = 0.0
                dictInv['DC_Voltage_SF'] = 0.0
                dictInv['DC_Power_SF'] = 0.0
                dictInv['Temp_SF'] = 0.0

                logger.debug(f'Inverter')
                for j, k in dictInv.items():
                    logger.debug(f'  {j}: {k}')

                publish_metrics(dictInv, 'inverter', '')
                logger.debug('Done publishing inverter metrics...')

                datapoint['time'] = str(datetime.datetime.utcnow().replace(
                    tzinfo=datetime.timezone.utc).isoformat())

                logger.debug(f'Writing to Influx: {str(datapoint)}')
                await solar_client.write(datapoint)

            else:
                # Error during data receive
                if client.last_error() == 2:
                    logger.error(
                        f'Failed to connect to SolarEdge inverter {client.host()}!'
                    )
                elif client.last_error() == 3 or client.last_error() == 4:
                    logger.error('Send or receive error!')
                elif client.last_error() == 5:
                    logger.error('Timeout during send or receive operation!')
                await asyncio.sleep(period)

            for x in range(1, mbmeters + 1):
                # Now loop through this for each meter that is attached.
                logger.debug(f'Meter={str(x)}')
                reg_block = {}
                dictM = {}

                # Start point is different for each meter
                if x == 1:
                    reg_block = client.read_holding_registers(40188, 105)
                if x == 2:
                    reg_block = client.read_holding_registers(40362, 105)
                if x == 3:
                    reg_block = client.read_holding_registers(40537, 105)
                if reg_block:
                    # print(reg_block)
                    # reg_block[0] = AC Total current value
                    # reg_block[1] = AC Phase A current value
                    # reg_block[2] = AC Phase B current value
                    # reg_block[3] = AC Phase C current value
                    # reg_block[4] = AC current scale factor
                    # reg_block[5] = AC Phase Line (average) to N voltage value
                    # reg_block[6] = AC Phase A to N voltage value
                    # reg_block[7] = AC Phase B to N voltage value
                    # reg_block[8] = AC Phase C to N voltage value
                    # reg_block[9] = AC Phase Line to Line voltage value
                    # reg_block[10] = AC Phase A to B voltage value
                    # reg_block[11] = AC Phase B to C voltage value
                    # reg_block[12] = AC Phase C to A voltage value
                    # reg_block[13] = AC voltage scale factor
                    # reg_block[14] = AC Frequency value
                    # reg_block[15] = AC Frequency scale factor
                    # reg_block[16] = Total Real Power
                    # reg_block[17] = Phase A Real Power
                    # reg_block[18] = Phase B Real Power
                    # reg_block[19] = Phase C Real Power
                    # reg_block[20] = Real Power scale factor
                    # reg_block[21] = Total Apparent Power
                    # reg_block[22] = Phase A Apparent Power
                    # reg_block[23] = Phase B Apparent Power
                    # reg_block[24] = Phase C Apparent Power
                    # reg_block[25] = Apparent Power scale factor
                    # reg_block[26] = Total Reactive Power
                    # reg_block[27] = Phase A Reactive Power
                    # reg_block[28] = Phase B Reactive Power
                    # reg_block[29] = Phase C Reactive Power
                    # reg_block[30] = Reactive Power scale factor
                    # reg_block[31] = Average Power Factor
                    # reg_block[32] = Phase A Power Factor
                    # reg_block[33] = Phase B Power Factor
                    # reg_block[34] = Phase C Power Factor
                    # reg_block[35] = Power Factor scale factor
                    # reg_block[36] = Total Exported Real Energy
                    # reg_block[38] = Phase A Exported Real Energy
                    # reg_block[40] = Phase B Exported Real Energy
                    # reg_block[42] = Phase C Exported Real Energy
                    # reg_block[44] = Total Imported Real Energy
                    # reg_block[46] = Phase A Imported Real Energy
                    # reg_block[48] = Phase B Imported Real Energy
                    # reg_block[50] = Phase C Imported Real Energy
                    # reg_block[52] = Real Energy scale factor
                    # reg_block[53] = Total Exported Real Energy
                    # reg_block[55] = Phase A Exported Real Energy
                    # reg_block[57] = Phase B Exported Real Energy
                    # reg_block[59] = Phase C Exported Real Energy
                    # reg_block[61] = Total Imported Real Energy
                    # reg_block[63] = Phase A Imported Real Energy
                    # reg_block[65] = Phase B Imported Real Energy
                    # reg_block[67] = Phase C Imported Real Energy
                    # reg_block[69] = Real Energy scale factor
                    logger.debug(f'meter reg_block: {str(reg_block)}')

                    # Set the Label to use for the Meter Metrics for Prometheus
                    metriclabel = dictMeterLabel[x - 1]
                    # Clear data from inverter, otherwise we publish that again!
                    datapoint = {
                        'measurement': 'SolarEdge',
                        'tags': {
                            'meter': dictMeterLabel[x - 1]
                        },
                        'fields': {}
                    }

                    data = BinaryPayloadDecoder.fromRegisters(
                        reg_block, byteorder=Endian.Big, wordorder=Endian.Big)

                    # SunSpec DID
                    # Register 40188
                    fooVal = trunc_float(data.decode_16bit_uint())
                    fooName = 'M_SunSpec_DID'
                    if fooVal < 65535:
                        dictM[fooName] = fooVal
                    else:
                        dictM[fooName] = 0.0

                    # SunSpec Length
                    # Register 40070
                    fooVal = trunc_float(data.decode_16bit_uint())
                    fooName = 'M_SunSpec_Length'
                    if fooVal < 65535:
                        dictM[fooName] = fooVal
                    else:
                        dictM[fooName] = 0.0

                    # AC Current
                    data.skip_bytes(8)
                    # Register 40194
                    scalefactor = 10**data.decode_16bit_int()
                    data.skip_bytes(-10)
                    # Register 40190-40193
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_Current'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_CurrentA'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_CurrentB'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_CurrentC'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0

                # AC Voltage
                    data.skip_bytes(18)
                    # Register 40203
                    scalefactor = 10**data.decode_16bit_int()
                    data.skip_bytes(-18)
                    # Register 40195-40202
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_VoltageLN'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_VoltageAN'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_VoltageBN'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_VoltageCN'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_VoltageLL'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_VoltageAB'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_VoltageBC'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_VoltageCA'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0

                    # AC Frequency
                    data.skip_bytes(4)
                    # Register 40205
                    scalefactor = 10**data.decode_16bit_int()
                    data.skip_bytes(-4)
                    # Register 40204
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_Frequency'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0

                    # AC Real Power
                    data.skip_bytes(10)
                    # Register 40210
                    scalefactor = 10**data.decode_16bit_int()
                    data.skip_bytes(-10)
                    # Register 40206-40209
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_Power'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_Power_A'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_Power_B'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_Power_C'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0

                    # AC Apparent Power
                    data.skip_bytes(10)
                    # Register 40215
                    scalefactor = 10**data.decode_16bit_int()
                    data.skip_bytes(-10)
                    # Register 40211-40214
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_VA'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_VA_A'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_VA_B'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_VA_C'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0

                    # AC Reactive Power
                    data.skip_bytes(10)
                    # Register 40220
                    scalefactor = 10**data.decode_16bit_int()
                    data.skip_bytes(-10)
                    # Register 40216-40219
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_VAR'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_VAR_A'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_VAR_B'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_VAR_C'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0

                    # AC Power Factor
                    data.skip_bytes(10)
                    # Register 40225
                    scalefactor = 10**data.decode_16bit_int()
                    data.skip_bytes(-10)
                    # Register 40221-40224
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_PF'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_PF_A'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_PF_B'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_16bit_int())
                    fooName = 'M_AC_PF_C'
                    if fooVal < 32768:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0

                    # Accumulated AC Real Energy
                    data.skip_bytes(34)
                    # Register 40242
                    scalefactor = 10**data.decode_16bit_int()
                    data.skip_bytes(-34)
                    # Register 40226-40240
                    fooVal = trunc_float(data.decode_32bit_uint())
                    fooName = 'M_Exported'
                    if fooVal < 4294967295:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_32bit_uint())
                    fooName = 'M_Exported_A'
                    if fooVal < 4294967295:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_32bit_uint())
                    fooName = 'M_Exported_B'
                    if fooVal < 4294967295:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_32bit_uint())
                    fooName = 'M_Exported_C'
                    if fooVal < 4294967295:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_32bit_uint())
                    fooName = 'M_Imported'
                    if fooVal < 4294967295:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_32bit_uint())
                    fooName = 'M_Imported_A'
                    if fooVal < 4294967295:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_32bit_uint())
                    fooName = 'M_Imported_B'
                    if fooVal < 4294967295:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0
                    fooVal = trunc_float(data.decode_32bit_uint())
                    fooName = 'M_Imported_C'
                    if fooVal < 4294967295:
                        dictM[fooName] = fooVal * scalefactor
                    else:
                        dictM[fooName] = 0.0

                    # Accumulated AC Apparent Energy
                    #logger.debug(f'Apparent Energy SF: {str(np.int16(reg_block[69]))}')
                    #scalefactor = np.float_power(10,np.int16(reg_block[69]))
                    #datapoint['fields']['M_Exported_VA'] = trunc_float(((reg_block[53] << 16) + reg_block[54]) * scalefactor)
                    #datapoint['fields']['M_Exported_VA_A'] = trunc_float(((reg_block[55] << 16) + reg_block[56]) * scalefactor)
                    #datapoint['fields']['M_Exported_VA_B'] = trunc_float(((reg_block[57] << 16) + reg_block[58]) * scalefactor)
                    #datapoint['fields']['M_Exported_VA_C'] = trunc_float(((reg_block[59] << 16) + reg_block[60]) * scalefactor)
                    #datapoint['fields']['M_Imported_VA'] = trunc_float(((reg_block[61] << 16) + reg_block[62]) * scalefactor)
                    #datapoint['fields']['M_Imported_VA_A'] = trunc_float(((reg_block[63] << 16) + reg_block[64]) * scalefactor)
                    #datapoint['fields']['M_Imported_VA_B'] = trunc_float(((reg_block[65] << 16) + reg_block[66]) * scalefactor)
                    #datapoint['fields']['M_Imported_VA_C'] = trunc_float(((reg_block[67] << 16) + reg_block[68]) * scalefactor)

                    # Add the ScaleFactor elements
                    dictM['M_AC_Current_SF'] = 0.0
                    dictM['M_AC_Voltage_SF'] = 0.0
                    dictM['M_AC_Frequency_SF'] = 0.0
                    dictM['M_AC_Power_SF'] = 0.0
                    dictM['M_AC_VA_SF'] = 0.0
                    dictM['M_AC_VAR_SF'] = 0.0
                    dictM['M_AC_PF_SF'] = 0.0
                    dictM['M_Energy_W_SF'] = 0.0

                    publish_metrics(dictM, 'meter', metriclabel, x,
                                    legacysupport)

                    datapoint['time'] = str(datetime.datetime.utcnow().replace(
                        tzinfo=datetime.timezone.utc).isoformat())

                    logger.debug(f'Meter: {metriclabel}')
                    for j, k in dictM.items():
                        logger.debug(f'  {j}: {k}')

                    logger.debug(f'Writing to Influx: {str(datapoint)}')
                    await solar_client.write(datapoint)

                else:
                    # Error during data receive
                    if client.last_error() == 2:
                        logger.error(
                            f'Failed to connect to SolarEdge inverter {client.host()}!'
                        )
                    elif client.last_error() == 3 or client.last_error() == 4:
                        logger.error('Send or receive error!')
                    elif client.last_error() == 5:
                        logger.error(
                            'Timeout during send or receive operation!')
                    await asyncio.sleep(period)

        except InfluxDBWriteError as e:
            logger.error(f'Failed to write to InfluxDb: {e}')
        except IOError as e:
            logger.error(f'I/O exception during operation: {e}')
        except Exception as e:
            logger.error(f'Unhandled exception: {e}')

        await asyncio.sleep(period)
Example #38
0
    def onHeartbeat(self):
        #Domoticz.Log("onHeartbeat called")

        # Wich serial port settings to use?
        if (Parameters["Mode3"] == "S1B7PN"):
            StopBits, ByteSize, Parity = 1, 7, "N"
        if (Parameters["Mode3"] == "S1B7PE"):
            StopBits, ByteSize, Parity = 1, 7, "E"
        if (Parameters["Mode3"] == "S1B7PO"):
            StopBits, ByteSize, Parity = 1, 7, "O"
        if (Parameters["Mode3"] == "S1B8PN"):
            StopBits, ByteSize, Parity = 1, 8, "N"
        if (Parameters["Mode3"] == "S1B8PE"):
            StopBits, ByteSize, Parity = 1, 8, "E"
        if (Parameters["Mode3"] == "S1B8PO"):
            StopBits, ByteSize, Parity = 1, 8, "O"
        if (Parameters["Mode3"] == "S2B7PN"):
            StopBits, ByteSize, Parity = 2, 7, "N"
        if (Parameters["Mode3"] == "S2B7PE"):
            StopBits, ByteSize, Parity = 2, 7, "E"
        if (Parameters["Mode3"] == "S2B7PO"):
            StopBits, ByteSize, Parity = 2, 7, "O"
        if (Parameters["Mode3"] == "S2B8PN"):
            StopBits, ByteSize, Parity = 2, 8, "N"
        if (Parameters["Mode3"] == "S2B8PE"):
            StopBits, ByteSize, Parity = 2, 8, "E"
        if (Parameters["Mode3"] == "S2B8PO"):
            StopBits, ByteSize, Parity = 2, 8, "O"

        # How many registers to read (depending on data type)?
        registercount = 1  # Default
        if (Parameters["Mode6"] == "noco"): registercount = 1
        if (Parameters["Mode6"] == "int8"): registercount = 1
        if (Parameters["Mode6"] == "int16"): registercount = 1
        if (Parameters["Mode6"] == "int32"): registercount = 2
        if (Parameters["Mode6"] == "int64"): registercount = 4
        if (Parameters["Mode6"] == "uint8"): registercount = 1
        if (Parameters["Mode6"] == "uint16"): registercount = 1
        if (Parameters["Mode6"] == "uint32"): registercount = 2
        if (Parameters["Mode6"] == "uint64"): registercount = 4
        if (Parameters["Mode6"] == "float32"): registercount = 2
        if (Parameters["Mode6"] == "float64"): registercount = 4
        if (Parameters["Mode6"] == "string2"): registercount = 2
        if (Parameters["Mode6"] == "string4"): registercount = 4
        if (Parameters["Mode6"] == "string6"): registercount = 6
        if (Parameters["Mode6"] == "string8"): registercount = 8

        ###################################
        # pymodbus: RTU / ASCII
        ###################################
        if (Parameters["Mode1"] == "rtu" or Parameters["Mode1"] == "ascii"):
            Domoticz.Debug("MODBUS DEBUG USB SERIAL HW - Port=" +
                           Parameters["SerialPort"] + ", BaudRate=" +
                           Parameters["Mode2"] + ", StopBits=" +
                           str(StopBits) + ", ByteSize=" + str(ByteSize) +
                           " Parity=" + Parity)
            Domoticz.Debug("MODBUS DEBUG USB SERIAL CMD - Method=" +
                           Parameters["Mode1"] + ", Address=" +
                           Parameters["Address"] + ", Register=" +
                           Parameters["Password"] + ", Function=" +
                           Parameters["Username"] + ", Data type=" +
                           Parameters["Mode6"])
            try:
                client = ModbusSerialClient(method=Parameters["Mode1"],
                                            port=Parameters["SerialPort"],
                                            stopbits=StopBits,
                                            bytesize=ByteSize,
                                            parity=Parity,
                                            baudrate=int(Parameters["Mode2"]),
                                            timeout=1,
                                            retries=2)
            except:
                Domoticz.Log("Error opening Serial interface on " +
                             Parameters["SerialPort"])
                Devices[1].Update(0, "0")  # Update device in Domoticz

        ###################################
        # pymodbus: RTU over TCP
        ###################################
        if (Parameters["Mode1"] == "rtutcp"):
            Domoticz.Debug("MODBUS DEBUG TCP CMD - Method=" +
                           Parameters["Mode1"] + ", Address=" +
                           Parameters["Address"] + ", Port=" +
                           Parameters["Port"] + ", Register=" +
                           Parameters["Password"] + ", Data type=" +
                           Parameters["Mode6"])
            try:
                client = ModbusTcpClient(host=Parameters["Address"],
                                         port=int(Parameters["Port"]),
                                         timeout=5)
            except:
                Domoticz.Log("Error opening TCP interface on address: " +
                             Parameters["Address"])
                Devices[1].Update(0, "0")  # Update device in Domoticz

        ###################################
        # pymodbusTCP: TCP/IP
        ###################################
        if (Parameters["Mode1"] == "tcpip"):
            Domoticz.Debug("MODBUS DEBUG TCP CMD - Method=" +
                           Parameters["Mode1"] + ", Address=" +
                           Parameters["Address"] + ", Port=" +
                           Parameters["Port"] + ", Register=" +
                           Parameters["Password"] + ", Data type=" +
                           Parameters["Mode6"])
            try:
                client = ModbusClient(host=Parameters["Address"],
                                      port=int(Parameters["Port"]),
                                      auto_open=True,
                                      auto_close=True,
                                      timeout=5)
            except:
                Domoticz.Log("Error opening TCP/IP interface on address: " +
                             Parameters["Address"])
                Devices[1].Update(0, "0")  # Update device in Domoticz

        ###################################
        # pymodbus section
        ###################################
        if (Parameters["Mode1"] == "rtu" or Parameters["Mode1"] == "ascii"
                or Parameters["Mode1"] == "rtutcp"):
            try:
                # Which function to execute? RTU/ASCII/RTU over TCP
                if (Parameters["Username"] == "1"):
                    data = client.read_coils(int(Parameters["Password"]),
                                             registercount,
                                             unit=int(Parameters["Address"]))
                if (Parameters["Username"] == "2"):
                    data = client.read_discrete_inputs(
                        int(Parameters["Password"]),
                        registercount,
                        unit=int(Parameters["Address"]))
                if (Parameters["Username"] == "3"):
                    data = client.read_holding_registers(
                        int(Parameters["Password"]),
                        registercount,
                        unit=int(Parameters["Address"]))
                if (Parameters["Username"] == "4"):
                    data = client.read_input_registers(
                        int(Parameters["Password"]),
                        registercount,
                        unit=int(Parameters["Address"]))
                Domoticz.Debug("MODBUS DEBUG RESPONSE: " + str(data))
            except:
                Domoticz.Log(
                    "Modbus error communicating! (RTU/ASCII/RTU over TCP), check your settings!"
                )
                Devices[1].Update(0, "0")  # Update device to OFF in Domoticz

            try:
                # How to decode the input?
                decoder = BinaryPayloadDecoder.fromRegisters(
                    data.registers, byteorder=Endian.Big, wordorder=Endian.Big)
                if (Parameters["Mode6"] == "noco"): value = data.registers[0]
                if (Parameters["Mode6"] == "int8"):
                    value = decoder.decode_8bit_int()
                if (Parameters["Mode6"] == "int16"):
                    value = decoder.decode_16bit_int()
                if (Parameters["Mode6"] == "int32"):
                    value = decoder.decode_32bit_int()
                if (Parameters["Mode6"] == "int64"):
                    value = decoder.decode_64bit_int()
                if (Parameters["Mode6"] == "uint8"):
                    value = decoder.decode_8bit_uint()
                if (Parameters["Mode6"] == "uint16"):
                    value = decoder.decode_16bit_uint()
                if (Parameters["Mode6"] == "uint32"):
                    value = decoder.decode_32bit_uint()
                if (Parameters["Mode6"] == "uint64"):
                    value = decoder.decode_64bit_uint()
                if (Parameters["Mode6"] == "float32"):
                    value = decoder.decode_32bit_float()
                if (Parameters["Mode6"] == "float64"):
                    value = decoder.decode_64bit_float()
                if (Parameters["Mode6"] == "string2"):
                    value = decoder.decode_string(2)
                if (Parameters["Mode6"] == "string4"):
                    value = decoder.decode_string(4)
                if (Parameters["Mode6"] == "string6"):
                    value = decoder.decode_string(6)
                if (Parameters["Mode6"] == "string8"):
                    value = decoder.decode_string(8)
                Domoticz.Debug("MODBUS DEBUG VALUE: " + str(value))

                # Divide the value (decimal)?
                if (Parameters["Mode5"] == "div0"): value = str(value)
                if (Parameters["Mode5"] == "div10"):
                    value = str(round(value / 10, 1))
                if (Parameters["Mode5"] == "div100"):
                    value = str(round(value / 100, 2))
                if (Parameters["Mode5"] == "div1000"):
                    value = str(round(value / 1000, 3))

                Devices[1].Update(0, value)  # Update value in Domoticz

            except:
                Domoticz.Log(
                    "Modbus error decoding or recieved no data (RTU/ASCII/RTU over TCP)!, check your settings!"
                )
                Devices[1].Update(0, "0")  # Update value in Domoticz

        ###################################
        # pymodbusTCP section
        ###################################
        if (Parameters["Mode1"] == "tcpip"):
            try:
                # Which function to execute? TCP/IP
                if (Parameters["Username"] == "1"):
                    data = client.read_coils(int(Parameters["Password"]),
                                             registercount)
                if (Parameters["Username"] == "2"):
                    data = client.read_discrete_inputs(
                        int(Parameters["Password"]), registercount)
                if (Parameters["Username"] == "3"):
                    data = client.read_holding_registers(
                        int(Parameters["Password"]), registercount)
                if (Parameters["Username"] == "4"):
                    data = client.read_input_registers(
                        int(Parameters["Password"]), registercount)
                Domoticz.Debug("MODBUS DEBUG RESPONSE: " + str(data[0]))
            except:
                Domoticz.Log(
                    "Modbus error communicating! (TCP/IP), check your settings!"
                )
                Devices[1].Update(0, "0")  # Update device to OFF in Domoticz

            try:
                # How to decode the input?
                decoder = BinaryPayloadDecoder.fromRegisters(
                    data, byteorder=Endian.Big, wordorder=Endian.Big)
                if (Parameters["Mode6"] == "noco"): value = data[0]
                if (Parameters["Mode6"] == "int8"):
                    value = decoder.decode_8bit_int()
                if (Parameters["Mode6"] == "int16"):
                    value = decoder.decode_16bit_int()
                if (Parameters["Mode6"] == "int32"):
                    value = decoder.decode_32bit_int()
                if (Parameters["Mode6"] == "int64"):
                    value = decoder.decode_64bit_int()
                if (Parameters["Mode6"] == "uint8"):
                    value = decoder.decode_8bit_uint()
                if (Parameters["Mode6"] == "uint16"):
                    value = decoder.decode_16bit_uint()
                if (Parameters["Mode6"] == "uint32"):
                    value = decoder.decode_32bit_uint()
                if (Parameters["Mode6"] == "uint64"):
                    value = decoder.decode_64bit_uint()
                if (Parameters["Mode6"] == "float32"):
                    value = decoder.decode_32bit_float()
                if (Parameters["Mode6"] == "float64"):
                    value = decoder.decode_64bit_float()
                if (Parameters["Mode6"] == "string2"):
                    value = decoder.decode_string(2)
                if (Parameters["Mode6"] == "string4"):
                    value = decoder.decode_string(4)
                if (Parameters["Mode6"] == "string6"):
                    value = decoder.decode_string(6)
                if (Parameters["Mode6"] == "string8"):
                    value = decoder.decode_string(8)
                Domoticz.Debug("MODBUS DEBUG VALUE: " + str(value))

                # Divide the value (decimal)?
                if (Parameters["Mode5"] == "div0"): value = str(value)
                if (Parameters["Mode5"] == "div10"):
                    value = str(round(value / 10, 1))
                if (Parameters["Mode5"] == "div100"):
                    value = str(round(value / 100, 2))
                if (Parameters["Mode5"] == "div1000"):
                    value = str(round(value / 1000, 3))

                Devices[1].Update(0, value)  # Update value in Domoticz

            except:
                Domoticz.Log(
                    "Modbus error decoding or recieved no data (TCP/IP)!, check your settings!"
                )
                Devices[1].Update(0, "0")  # Update value in Domoticz
Example #39
0
def get_pv_data(host, port, modbusid, registers):
    client = ModbusClient(host=host, port=port)

    # connects even within if clause
    if client.connect() == False:
        print('Modbus Connection Error: Could not connect to', host)
        return None

    data = {}  ## empty data store for current values

    for myreg in registers:
        ## if the connection is somehow not possible (e.g. target not responding)
        #  show a error message instead of excepting and stopping
        try:
            addr = int(myreg[0])
            dt = myreg[1]
            received = client.read_input_registers(address=addr,
                                                   count=modbusdatatype[dt],
                                                   unit=int(modbusid))
        except Exception as e:
            thisdate = str(datetime.datetime.now()).partition('.')[0]
            thiserrormessage = thisdate + 'Modbus: Connection not possible. Check settings or connection.'
            print(thiserrormessage)
            print(traceback.format_exc())
            return None  ## prevent further execution of this function

        name = myreg[3]
        message = BinaryPayloadDecoder.fromRegisters(received.registers,
                                                     byteorder=Endian.Big,
                                                     wordorder=Endian.Big)
        ## provide the correct result depending on the defined datatype
        if myreg[1] == 'S32':
            interpreted = message.decode_32bit_int()
        elif myreg[1] == 'U32':
            interpreted = message.decode_32bit_uint()
        elif myreg[1] == 'U64':
            interpreted = message.decode_64bit_uint()
        elif myreg[1] == 'STR32':
            interpreted = message.decode_string(32)
        elif myreg[1] == 'S16':
            interpreted = message.decode_16bit_int()
        elif myreg[1] == 'U16':
            interpreted = message.decode_16bit_uint()
        else:  ## if no data type is defined do raw interpretation of the delivered data
            interpreted = message.decode_16bit_uint()

        ## check for "None" data before doing anything else
        if ((interpreted == MIN_SIGNED) or (interpreted == MAX_UNSIGNED)):
            value = None
        else:
            ## put the data with correct formatting into the data table
            if myreg[2] == 'FIX3':
                value = float(interpreted) / 1000
            elif myreg[2] == 'FIX2':
                value = float(interpreted) / 100
            elif myreg[2] == 'FIX1':
                value = float(interpreted) / 10
            elif myreg[2] == 'UTF8':
                value = str(interpreted, 'UTF-8',
                            errors='ignore').rstrip("\x00")
            elif myreg[2] == 'ENUM':
                e = pvenums.get(name, {})
                value = e.get(interpreted, str(interpreted))
            else:
                value = interpreted
        data[name] = value

    client.close()
    return data
Example #40
0
    def onStart(self):

        self.uTEa = 1
        self.uTEb = 6
        self.uTU1 = 3
        self.uTU2 = 4
        self.uPowerCur = 8
        self.uControlMode = 9
        #self.uPowerReq = 10
        self.uModeCur = 7
        #self.uModeReq = 11
        self.uIN1 = 12
        self.uIN2 = 13
        self.uD1 = 14
        self.uD2 = 15
        self.uD3 = 16
        self.uD4 = 17
        self.uZVT = 18
        self.uBypass = 19
        self.uAlarmFilter = 20
        self.uHeatingSeason = 21
        self.uNightlyCooling = 22

        # CMDs:
        #  init: pygettext3.8 -d base -o locales/base.pot plugin.py
        #  init: locales/cs/LC_MESSAGES# msgfmt -o base.mo base
        #  update: xgettext -d base --from-code utf-8 -s -j -o locales/base.pot plugin.py
        #  update: msgmerge --update locales/cs/LC_MESSAGES/base.po locales/base.pot
        #  update: locales/cs/LC_MESSAGES# msgfmt -o base.mo base
        translate = gettext.translation('base',
                                        localedir='plugins/atrea/locales',
                                        fallback=True,
                                        languages=['cs'])
        translate.install()
        self._ = translate.gettext

        if (Parameters["SerialPort"] == "1"):
            Domoticz.Debugging(1)
            DumpConfigToLog()
            Domoticz.Debug("Domoticz language: " +
                           Settings["Language"])  # Domoticz language: cs
            Domoticz.Debug("***** NOTIFICATION: Debug is enabled!")
        else:
            Domoticz.Debugging(0)
        Domoticz.Debug("onStart called")

        Domoticz.Heartbeat(int(10))  # Device pollrate (heartbeat) : 10s

        self.TCP_IP = Parameters["Address"]
        self.TCP_PORT = 502

        self.labelIN1 = str(Parameters["Mode1"])
        self.labelIN2 = str(Parameters["Mode2"])
        self.labelD1 = str(Parameters["Mode3"])
        self.labelD2 = str(Parameters["Mode4"])
        self.labelD3 = str(Parameters["Mode5"])
        self.labelD4 = str(Parameters["Mode6"])

        self.atreaMinPower = 60

        # Get Atrea unit info from Modbus..
        try:
            client = ModbusClient(host=self.TCP_IP,
                                  port=int(self.TCP_PORT),
                                  unit_id=int(1),
                                  auto_open=True,
                                  auto_close=True,
                                  timeout=2)
        except:
            Domoticz.Error("Can not connect to Modbus TCP/IP: " + self.TCP_IP +
                           ":" + self.TCP_PORT)
        try:
            # 1 = 180 EC, 2 = 190 ECV, 3 = 370 EC, 4 = 390ECV, 5 = 510 EC, 6 = 520 ECV
            self.atreaType = BinaryPayloadDecoder.fromRegisters(
                client.read_holding_registers(509, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            if (self.atreaType == 1):
                self.atreaTypeStr = "180 EC"
                self.atreaNominalPower = 180
            elif (self.atreaType == 2):
                self.atreaTypeStr = "190 ECV"
                self.atreaNominalPower = 180
            elif (self.atreaType == 3):
                self.atreaTypeStr = "370 EC"
                self.atreaNominalPower = 370
            elif (self.atreaType == 4):
                self.atreaTypeStr = "390 ECV"
                self.atreaNominalPower = 370
            elif (self.atreaType == 5):
                self.atreaTypeStr = "510 EC"
                self.atreaNominalPower = 510
            elif (self.atreaType == 6):
                self.atreaTypeStr = "520 ECV"
                self.atreaNominalPower = 510
            Domoticz.Debug("Atrea type: " + self.atreaTypeStr)

            self.atreaLimitedPower = BinaryPayloadDecoder.fromRegisters(
                client.read_holding_registers(516, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            self.atreaMaxPower = self.atreaLimitedPower / 100 * self.atreaNominalPower
            Domoticz.Debug("Atrea limited power at: " +
                           str(self.atreaLimitedPower) + "% = " +
                           str(self.atreaMaxPower) + "m3")

            self.atreaIN1type = BinaryPayloadDecoder.fromRegisters(
                client.read_holding_registers(705, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            self.atreaIN2type = BinaryPayloadDecoder.fromRegisters(
                client.read_holding_registers(704, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            self.atreaZVT = BinaryPayloadDecoder.fromRegisters(
                client.read_holding_registers(514, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()

        except:
            Domoticz.Error("Modbus TCP/IP communication error. Check it out!")

        if self.uTEa not in Devices:
            Domoticz.Device(Unit=self.uTEa,
                            DeviceID="TEa",
                            Name=self._("Outside temperature"),
                            TypeName="Temperature",
                            Used=1).Create()
        if self.uTEb not in Devices:
            Domoticz.Device(Unit=self.uTEb,
                            DeviceID="TEb",
                            Name=self._("Exhaust air before recuperation"),
                            TypeName="Temperature",
                            Used=1).Create()
        if self.uTU1 not in Devices:
            Domoticz.Device(Unit=self.uTU1,
                            DeviceID="TU1",
                            Name=self._("Fresh air after recuperation"),
                            TypeName="Temperature",
                            Used=1).Create()
        if self.uTU2 not in Devices:
            Domoticz.Device(Unit=self.uTU2,
                            DeviceID="TU2",
                            Name=self._("Exhaust air after recuperation"),
                            TypeName="Temperature",
                            Used=1).Create()
        if self.labelD1 != "" and self.labelD1 != "D1" and self.uD1 not in Devices:
            Domoticz.Device(Unit=self.uD1,
                            DeviceID="D1",
                            Name=self.labelD1,
                            TypeName="Contact",
                            Used=1).Create()
        if self.labelD2 != "" and self.labelD2 != "D2" and self.uD2 not in Devices:
            Domoticz.Device(Unit=self.uD2,
                            DeviceID="D2",
                            Name=self.labelD2,
                            TypeName="Contact",
                            Used=1).Create()
        if self.labelD3 != "" and self.labelD3 != "D3" and self.uD3 not in Devices:
            Domoticz.Device(Unit=self.uD3,
                            DeviceID="D3",
                            Name=self.labelD3,
                            TypeName="Contact",
                            Used=1).Create()
        if self.labelD4 != "" and self.labelD4 != "D4" and self.uD4 not in Devices:
            Domoticz.Device(Unit=self.uD4,
                            DeviceID="D4",
                            Name=self.labelD4,
                            TypeName="Contact",
                            Used=1).Create()
        if self.atreaZVT > 0 and self.uZVT not in Devices:
            Domoticz.Device(Unit=self.uZVT,
                            DeviceID="ZVT",
                            Name=self._("Ground heat exchanger"),
                            TypeName="Contact",
                            Used=1).Create()
        if self.uBypass not in Devices:
            Domoticz.Device(Unit=self.uBypass,
                            DeviceID="BYPASS",
                            Name=self._("Bypass flap"),
                            TypeName="Contact",
                            Used=1).Create()
        if self.uAlarmFilter not in Devices:
            Domoticz.Device(Unit=self.uAlarmFilter,
                            DeviceID="AlarmFilter",
                            Name=self._("Filter change"),
                            Type=243,
                            Subtype=22,
                            Used=1).Create()
        if self.uHeatingSeason not in Devices:
            Domoticz.Device(Unit=self.uHeatingSeason,
                            DeviceID="HeatingSeason",
                            Name=self._("Heating season"),
                            Type=244,
                            Subtype=73,
                            Switchtype=0,
                            Image=10,
                            Used=1).Create()
        if self.uNightlyCooling not in Devices:
            Domoticz.Device(Unit=self.uNightlyCooling,
                            DeviceID="NightlyCooling",
                            Name=self._("Nightly cooling"),
                            Type=244,
                            Subtype=73,
                            Switchtype=0,
                            Image=16,
                            Used=1).Create()

        if self.labelIN1 != "" and self.labelIN1 != "IN1" and self.uIN1 not in Devices:
            # H00705 Režim vstupu IN1: 0 = Kontakt, 1 = Analog (0-10V)
            if self.atreaIN1type == 0: TypeName = "Contact"
            elif self.atreaIN1type == 1:  # analog
                if re.search('vlhko', self.labelIN1,
                             re.IGNORECASE) or re.search(
                                 'humid', self.labelIN1, re.IGNORECASE):
                    TypeName = "Humidity"
                elif re.search('teplot', self.labelIN1,
                               re.IGNORECASE) or re.search(
                                   'temp', self.labelIN1, re.IGNORECASE):
                    TypeName = "Temperature"
                else:
                    TypeName = "Percentage"
            Domoticz.Device(Unit=self.uIN1,
                            DeviceID="IN1",
                            Name=self.labelIN1,
                            TypeName=TypeName,
                            Used=1).Create()

        if self.labelIN2 != "" and self.labelIN2 != "IN2" and self.uIN2 not in Devices:
            # H00704 Režim vstupu IN2: 0 = Kontakt, 1 = Analog (0-10V), 2 = Teplota
            if self.atreaIN2type == 0: TypeName = "Contact"
            elif self.atreaIN2type == 2: TypeName = "Temperature"
            elif self.atreaIN2type == 1:  # analog
                if re.search('vlhko', self.labelIN2,
                             re.IGNORECASE) or re.search(
                                 'humid', self.labelIN2, re.IGNORECASE):
                    TypeName = "Humidity"
                elif re.search('teplot', self.labelIN2,
                               re.IGNORECASE) or re.search(
                                   'temp', self.labelIN2, re.IGNORECASE):
                    TypeName = "Temperature"
                else:
                    TypeName = "Percentage"
            Domoticz.Device(Unit=self.uIN2,
                            DeviceID="IN2",
                            Name=self.labelIN2,
                            TypeName=TypeName,
                            Used=1).Create()

        o1 = 60 + (self.atreaMaxPower - 60) / 8
        o2 = o1 + (self.atreaMaxPower - 60) / 8
        o3 = o2 + (self.atreaMaxPower - 60) / 8
        o4 = o3 + (self.atreaMaxPower - 60) / 8
        o5 = o4 + (self.atreaMaxPower - 60) / 4
        self.oPower = {
            "LevelNames":
            "0|60|" + str(int(o1)) + "|" + str(int(o2)) + "|" + str(int(o3)) +
            "|" + str(int(o4)) + "|" + str(int(o5)) + "|" +
            str(int(self.atreaMaxPower))
        }
        self.oControlMode = {
            "LevelNames":
            "|" + self._("Manual") + "|" + self._("Automatic") + "|" +
            self._("Temporary"),
            "LevelOffHidden":
            "true",
            "SelectorStyle":
            "1"
        }
        self.oModeReq = {
            "LevelNames":
            self._("Off") + "|" + self._("Periodic ventilation") + "|" +
            self._("Ventilation"),
            "SelectorStyle":
            "1"
        }
        self.oModeCur = {
            "LevelNames":
            self._("Off") + "|" + self._("Periodic ventilation") + "|" +
            self._("Ventilation") + "|" + self.labelIN1 + "|" + self.labelIN2 +
            "|" + self.labelD1 + "|" + self.labelD2 + "|" + self.labelD3 +
            "|" + self.labelD4 + "|" + self._("Rise") + "|" +
            self._("Rundown") + "|" + self._("Defrosting the recuperator"),
            "SelectorStyle":
            "1"
        }

        if self.uControlMode not in Devices:
            Domoticz.Device(Unit=self.uControlMode,
                            DeviceID="ControlMode",
                            Name=self._("Ventilation control mode"),
                            Options=self.oControlMode,
                            Type=244,
                            Subtype=62,
                            Switchtype=18,
                            Image=9,
                            Used=1).Create()
        if self.uPowerCur not in Devices:
            Domoticz.Device(Unit=self.uPowerCur,
                            DeviceID="PowerCur",
                            Name=self._("Current ventilation power"),
                            Options=self.oPower,
                            Type=244,
                            Subtype=62,
                            Switchtype=18,
                            Image=7,
                            Used=1).Create()
        #if self.uPowerReq not in Devices: Domoticz.Device(Unit=self.uPowerReq, DeviceID="PowerReq", Name=self._("Requested ventilation power"), Options=self.oPower, Type=244, Subtype=62, Switchtype=18, Image=7, Used=1).Create()
        if self.uModeCur not in Devices:
            Domoticz.Device(Unit=self.uModeCur,
                            DeviceID="ModeCur",
                            Name=self._("Current ventilation mode"),
                            Options=self.oModeCur,
                            Image=7,
                            Type=244,
                            Subtype=62,
                            Switchtype=18,
                            Used=1).Create()
        #if self.uModeReq not in Devices: Domoticz.Device(Unit=self.uModeReq, DeviceID="ModeReq", Name=self._("Requested ventilation mode"), Options=self.oModeReq, Image=7, Type=244, Subtype=62, Switchtype=18, Used=1).Create()

        return
Example #41
0
    def _refresh(self):
        start_time = time.time()
        try:
        # myCounter = 1
            for pluggit_key in self._myTempReadDict:
                # logger.debug("Pluggit: ---------------------------------> Wir sind in der Refresh Schleife")
                values = self._modbusRegisterDic[pluggit_key]
                # logger.debug("Pluggit: Refresh Schleife: Inhalt von values ist {0}".format(values))
                # 2015-01-07 23:53:08,296 DEBUG    Pluggit      Pluggit: Refresh Schleife: Inhalt von values ist 168 -- __init__.py:_refresh:158
                item = self._myTempReadDict[pluggit_key]
                # logger.debug("Pluggit: Refresh Schleife: Inhalt von item ist {0}".format(item))
                # 2015-01-07 23:53:08,316 DEBUG    Pluggit      Pluggit: Refresh Schleife: Inhalt von item ist pluggit.unitMode -- __init__.py:_refresh:160

                #=======================================================#
                # read values from pluggit via modbus client registers
                #=======================================================#

                # logger.debug("Pluggit: ------------------------------------------> Wir sind vor dem Auslesen der Werte")
                registerValue = None
                registerValue = self._Pluggit.read_holding_registers(values, read_qty = 1).getRegister(0)
                # logger.debug("Pluggit: Read parameter '{0}' with register '{1}': Value is '{2}'".format(pluggit_key, values, registerValue))

                # week program: possible values 0-10
                if values == self._modbusRegisterDic['prmNumOfWeekProgram']:
                    registerValue += 1
                    item(registerValue, 'Pluggit')
                    # 2015-01-07 23:53:08,435 DEBUG    Pluggit      Item pluggit.unitMode = 8 via Pluggit None None -- item.py:__update:363
                    # logger.debug("Pluggit: Week Program Number: {0}".format(registerValue))
                    # 2015-01-07 23:53:08,422 DEBUG    Pluggit      Pluggit: Active Unit Mode: Week program -- __init__.py:_refresh:177

                # active unit mode
                if values == self._modbusRegisterDic['prmRamIdxUnitMode'] and registerValue == 8:
                    # logger.debug("Pluggit: Active Unit Mode: Week program")
                    item('Woche', 'Pluggit')
                if values == self._modbusRegisterDic['prmRamIdxUnitMode'] and registerValue == 4:
                    # logger.debug("Pluggit: Active Unit Mode: Manual")
                    item('Manuell', 'Pluggit')

                # fan speed
                if values == self._modbusRegisterDic['prmRomIdxSpeedLevel']:
                    # logger.debug("Pluggit: Fan Speed: {0}".format(registerValue))
                    item(registerValue, 'Pluggit')

                # remaining filter lifetime
                if values == self._modbusRegisterDic['prmFilterRemainingTime']:
                    # logger.debug("Pluggit: Remaining filter lifetime: {0}".format(registerValue))
                    item(registerValue, 'Pluggit')

                # bypass state
                if values == self._modbusRegisterDic['prmRamIdxBypassActualState'] and registerValue == 255:
                    # logger.debug("Pluggit: Bypass state: opened")
                    item('geöffnet', 'Pluggit')
                if values == self._modbusRegisterDic['prmRamIdxBypassActualState'] and registerValue == 0:
                    # logger.debug("Pluggit: Bypass state: closed")
                    item('geschlossen', 'Pluggit')

                # Temperatures
                # Frischluft außen
                if values == self._modbusRegisterDic['prmRamIdxT1']:
                    t1 = self._Pluggit.read_holding_registers(values, 2, unit=22)
                    decodert1 = BinaryPayloadDecoder.fromRegisters(t1.registers, endian=Endian.Big)
                    t1 = decodert1.decode_32bit_float()
                    t1 = round(t1, 2)
                    # logger.debug("Pluggit: Frischluft außen: {0:4.1f}".format(t1))
                    # logger.debug("Pluggit: Frischluft außen: {0}".format(t1))
                    item(t1, 'Pluggit')

                # Zuluft innen
                if values == self._modbusRegisterDic['prmRamIdxT2']:
                    t2 = self._Pluggit.read_holding_registers(values, 2, unit=22)
                    decodert2 = BinaryPayloadDecoder.fromRegisters(t2.registers, endian=Endian.Big)
                    t2 = decodert2.decode_32bit_float()
                    t2 = round(t2, 2)
                    # logger.debug("Pluggit: Zuluft innen: {0:4.1f}".format(t2))
                    # logger.debug("Pluggit: Zuluft innen: {0}".format(t2))
                    item(t2, 'Pluggit')

                # Abluft innen
                if values == self._modbusRegisterDic['prmRamIdxT3']:
                    t3 = self._Pluggit.read_holding_registers(values, 2, unit=22)
                    decodert3 = BinaryPayloadDecoder.fromRegisters(t3.registers, endian=Endian.Big)
                    t3 = decodert3.decode_32bit_float()
                    t3 = round(t3, 2)
                    # logger.debug("Pluggit: Abluft innen: {0:4.1f}".format(t3))
                    # logger.debug("Pluggit: Abluft innen: {0}".format(t3))
                    item(t3, 'Pluggit')

                # Fortluft außen
                if values == self._modbusRegisterDic['prmRamIdxT4']:
                    t4 = self._Pluggit.read_holding_registers(values, 2, unit=22)
                    decodert4 = BinaryPayloadDecoder.fromRegisters(t4.registers, endian=Endian.Big)
                    t4 = decodert4.decode_32bit_float()
                    t4 = round(t4, 2)
                    # logger.debug("Pluggit: Fortluft außen: {0:4.1f}".format(t4))
                    # logger.debug("Pluggit: Fortluft außen: {0}".format(t4))
                    item(t4, 'Pluggit')

                # logger.debug("Pluggit: ------------------------------------------> Ende der Schleife vor sleep, Durchlauf Nr. {0}".format(myCounter))
                time.sleep(0.1)
                # myCounter += 1

        except Exception as e:
            logger.error("Pluggit: something went wrong in the refresh function: {0}".format(e))
            return
        end_time = time.time()
        cycletime = end_time - start_time
        logger.debug("Pluggit: cycle took {0} seconds".format(cycletime))
Example #42
0
    def onHeartbeat(self):
        Domoticz.Debug("onHeartbeat called")

        try:
            client = ModbusClient(host=self.TCP_IP,
                                  port=int(self.TCP_PORT),
                                  unit_id=int(1),
                                  auto_open=True,
                                  auto_close=True,
                                  timeout=2)
        except:
            Domoticz.Error("Can not connect to Modbus TCP/IP: " + self.TCP_IP +
                           ":" + self.TCP_PORT)

        try:
            c207 = BinaryPayloadDecoder.fromRegisters(
                client.read_coils(207, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            c211 = BinaryPayloadDecoder.fromRegisters(
                client.read_coils(211, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            c902 = BinaryPayloadDecoder.fromRegisters(
                client.read_coils(902, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            c1200 = BinaryPayloadDecoder.fromRegisters(
                client.read_coils(1200, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            #Domoticz.Debug("Modbus response: v='" + str(i201) + "'")
        except:
            Domoticz.Error(
                "Modbus TCP/IP communication error (input registers). Check it out!"
            )

        try:
            i200 = BinaryPayloadDecoder.fromRegisters(
                client.read_input_registers(200, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            i201 = BinaryPayloadDecoder.fromRegisters(
                client.read_input_registers(201, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            i203 = BinaryPayloadDecoder.fromRegisters(
                client.read_input_registers(203, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            i204 = BinaryPayloadDecoder.fromRegisters(
                client.read_input_registers(204, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            i205 = BinaryPayloadDecoder.fromRegisters(
                client.read_input_registers(205, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            i206 = BinaryPayloadDecoder.fromRegisters(
                client.read_input_registers(206, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            #Domoticz.Debug("Modbus response: v='" + str(i201) + "'")
        except:
            Domoticz.Error(
                "Modbus TCP/IP communication error (input registers). Check it out!"
            )

        try:
            d200 = BinaryPayloadDecoder.fromRegisters(
                client.read_discrete_inputs(200, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            d201 = BinaryPayloadDecoder.fromRegisters(
                client.read_discrete_inputs(201, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            d202 = BinaryPayloadDecoder.fromRegisters(
                client.read_discrete_inputs(202, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            d203 = BinaryPayloadDecoder.fromRegisters(
                client.read_discrete_inputs(203, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            #Domoticz.Debug("Modbus response: v='" + str(i201) + "'")
        except:
            Domoticz.Error(
                "Modbus TCP/IP communication error (discrete inputs). Check it out!"
            )

        try:
            v1000 = BinaryPayloadDecoder.fromRegisters(
                client.read_holding_registers(1000, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            v1001 = BinaryPayloadDecoder.fromRegisters(
                client.read_holding_registers(1001, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            #v1008 = BinaryPayloadDecoder.fromRegisters(client.read_holding_registers(1008, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int()
            #v1009 = BinaryPayloadDecoder.fromRegisters(client.read_holding_registers(1009, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int()
            #v1012 = BinaryPayloadDecoder.fromRegisters(client.read_holding_registers(1012, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int()
            #v1013 = BinaryPayloadDecoder.fromRegisters(client.read_holding_registers(1013, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int()
            v1015 = BinaryPayloadDecoder.fromRegisters(
                client.read_holding_registers(1015, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            v1016 = BinaryPayloadDecoder.fromRegisters(
                client.read_holding_registers(1016, 1),
                byteorder=Endian.Big,
                wordorder=Endian.Big).decode_16bit_int()
            #Domoticz.Debug("Modbus response: v='" + str(v1015) + "'")
        except:
            Domoticz.Error(
                "Modbus TCP/IP communication error (holding registers). Check it out!"
            )

        # == Temperatures
        Devices[self.uTU1].Update(0, str(i200 / 10))
        Devices[self.uTU2].Update(0, str(i201 / 10))
        Devices[self.uTEa].Update(0, str(i203 / 10))
        Devices[self.uTEb].Update(0, str(i204 / 10))

        # == IN1 & IN2
        # I00205 Stav vstupu IN1 (0-10V): Analogový vstup: U= DATA/1000, Kontaktní vstup: rozepnuto ~ 3350 až 3450, sepnuto ~ do 20
        # I00206 Stav vstupu IN2 (0-10V): Analogový vstup: U= DATA/1000, Kontaktní vstup: rozepnuto ~ 3350 až 3450, sepnuto ~ do 20
        # kontakt: Statuses: Open: nValue = 1, Closed: nValue = 0
        if self.uIN1 in Devices:
            if self.atreaIN1type == "Contact":
                Devices[self.uIN1].Update(int(not (i205 <= 50)), "")
            elif Devices[self.uIN1].Type == 81:
                # Humidity_status can be one of:
                # 0=Normal      45~50, 55~60
                # 1=Comfortable 50~55
                # 2=Dry         <45
                # 3=Wet         >60
                if i205 < 4500: humstat = 2
                elif i205 > 6000: humstat = 3
                elif i205 >= 5000 and i205 <= 5500: humstat = 1
                else: humstat = 0
                Devices[self.uIN1].Update(int(i205 / 100), str(humstat))
            else:
                Devices[self.uIN1].Update(int(i205 / 100), str(i205 / 100))
        if self.uIN2 in Devices:
            if self.atreaIN2type == "Contact":
                Devices[self.uIN2].Update(int(not (i206 <= 50)), "")
            elif Devices[self.uIN2].Type == 81:
                if i206 < 4500: humstat = 2
                elif i206 > 6000: humstat = 3
                elif i206 >= 5000 and i206 <= 5500: humstat = 1
                else: humstat = 0
                Devices[self.uIN2].Update(int(i206 / 100), str(humstat))
            else:
                Devices[self.uIN2].Update(int(i206 / 100), str(i206 / 100))

        # == D1 & D2 & D3 & D4
        # D00200 Stav vstupu D1 : 0/1 : Vypnuto/Zapnuto
        # D00201 Stav vstupu D2 : 0/1 : Vypnuto/Zapnuto
        # D00202 Stav vstupu D3 : 0/1 : Vypnuto/Zapnuto
        # D00203 Stav vstupu D4 : 0/1 : Vypnuto/Zapnuto
        if self.uD1 in Devices: Devices[self.uD1].Update(int(d200 == 1), "")
        if self.uD2 in Devices: Devices[self.uD2].Update(int(d201 == 1), "")
        if self.uD3 in Devices: Devices[self.uD3].Update(int(d202 == 1), "")
        if self.uD4 in Devices: Devices[self.uD4].Update(int(d203 == 1), "")

        # == ZVT
        # C00207 0 = ZVT
        if self.uZVT in Devices: Devices[self.uZVT].Update(int(c207 == 0), "")

        # == Bypass
        # C00211 1 = Bypass flap
        if self.uBypass in Devices:
            Devices[self.uBypass].Update(int(c211 == 1), "")

        # == Heating season
        # C01200 1 = heating, 0 = non-heating
        if self.uHeatingSeason in Devices:
            Devices[self.uHeatingSeason].Update(int(c1200 == 1), "")

        # == Nightly Cooling
        # C00902 0 = recuperation, 1 = cooling
        if self.uNightlyCooling in Devices:
            Devices[self.uNightlyCooling].Update(int(c902 == 1), "")

        # == ControlMode
        if v1015 == 2 or v1016 == 2:
            Devices[self.uControlMode].Update(1, str(30))
        elif v1015 == 1 or v1016 == 1:
            Devices[self.uControlMode].Update(0, str(10))
        else:
            Devices[self.uControlMode].Update(0, str(20))

        # == PowerReq
        # H01009 Nastavení požadovaného výkonu, pokud H01016=1,   0 = Vyp, 12=12%,..., 100 = 100%
        # H01013 Nastavení požadovaného výkonu, pokud H01016=0/2, 0 = Vyp, 12=12%,..., 100 = 100%
        #if (v1016 == 1):   Devices[self.uPowerReq].Update(int(int(v1009) >= 10), str(self._powerPercentToDomoticzValue(v1009)))
        #elif (v1016 == 2): Devices[self.uPowerReq].Update(int(int(v1013) >= 10), str(self._powerPercentToDomoticzValue(v1013)))
        #elif (v1016 == 0): Devices[self.uPowerReq].Update(int(int(v1001) >= 10), str(self._powerPercentToDomoticzValue(v1001)))

        # == PowerCur
        # "0|60|90|120|150|180|240|300"
        Devices[self.uPowerCur].Update(
            int(int(v1001) >= 10),
            str(self._powerPercentToDomoticzValue(v1001)))

        # == ModeReq                                                  "Vypnuto |    Periodické větrání |    Větrání"
        # H01008 Nastavení požadovaného režimu, pokud H01015=1,                 0 = Periodické větrání, 1 = Větrání
        # H01012 Nastavení požadovaného režimu, pokud H01015= 0/2, 0 = Vypnuto, 1 = Periodické větrání, 2 = Větrání
        #if (v1015 == 1):
        #    if v1008 == 0:   Devices[self.uModeReq].Update(1, str(10))
        #    elif v1008 == 1: Devices[self.uModeReq].Update(1, str(20))
        #elif (v1015 == 2):
        #    if v1012 == 0:   Devices[self.uModeReq].Update(1, str(10))
        #    elif v1012 == 1: Devices[self.uModeReq].Update(1, str(20))
        #elif (v1015 == 0):
        #    if v1000 == 0:   Devices[self.uModeReq].Update(1, str(10))
        #    elif v1000 == 1: Devices[self.uModeReq].Update(1, str(20))

        # == ModeCur
        # "|Periodické větrání|Větrání|Čidlo vlhkosti|IN2|D1|D2|Koupelny+WC|Odsavač kuchyň|Náběh|Doběh|Odmrazování rekuperátoru"
        if (v1000 == 0):
            Devices[self.uModeCur].Update(int(int(v1001) >= 10), str(10))
        elif (v1000 == 1):
            Devices[self.uModeCur].Update(int(int(v1001) >= 10), str(20))
        elif (v1000 == 10):
            Devices[self.uModeCur].Update(1, str(30))
        elif (v1000 == 11):
            Devices[self.uModeCur].Update(1, str(40))
        elif (v1000 == 12):
            Devices[self.uModeCur].Update(1, str(50))
        elif (v1000 == 13):
            Devices[self.uModeCur].Update(1, str(60))
        elif (v1000 == 14):
            Devices[self.uModeCur].Update(1, str(70))
        elif (v1000 == 15):
            Devices[self.uModeCur].Update(1, str(80))
        elif (v1000 == 20):
            Devices[self.uModeCur].Update(1, str(90))
        elif (v1000 == 21):
            Devices[self.uModeCur].Update(1, str(100))
        elif (v1000 == 22):
            Devices[self.uModeCur].Update(1, str(110))

        # == Filter alarm from XML via HTTP
        try:
            bChangedFilter = True
            timeOfChange = 0
            xml = xmltodict.parse(
                requests.get("http://" + str(self.TCP_IP) +
                             "/config/alarms.xml").content)
            for i in xml['root']['errors']['i']:
                if int(i['@i']) == 100:
                    bChangedFilter = int(i['@p']) == 1
                    timeOfChange = i['@t']
            dtOfChange = datetime.fromtimestamp(int(timeOfChange))

            if bChangedFilter:
                Devices[self.uAlarmFilter].Update(
                    1,
                    self._("Filter last changed") + ": " + str(dtOfChange))
            else:
                Devices[self.uAlarmFilter].Update(
                    4,
                    self._("Filter to change since") + ": " + str(dtOfChange))
        except:
            Domoticz.Error(
                "Failed to get or process XML via HTML to get state of filter alarm."
            )

        return
Example #43
0
def getDataDecoder(registers):
    return BinaryPayloadDecoder.fromRegisters(
        registers,
        byteorder=Endian.Big,
        wordorder=Endian.Little)
Example #44
0
def run_binary_payload_ex():
    # ----------------------------------------------------------------------- #
    # We are going to use a simple client to send our requests
    # ----------------------------------------------------------------------- #
    client = ModbusClient('127.0.0.1', port=5440)
    client.connect()
    
    # ----------------------------------------------------------------------- #
    # If you need to build a complex message to send, you can use the payload
    # builder to simplify the packing logic.
    #
    # Here we demonstrate packing a random payload layout, unpacked it looks
    # like the following:
    #
    # - a 8 byte string 'abcdefgh'
    # - a 32 bit float 22.34
    # - a 16 bit unsigned int 0x1234
    # - another 16 bit unsigned int 0x5678
    # - an 8 bit int 0x12
    # - an 8 bit bitstring [0,1,0,1,1,0,1,0]
    # - an 32 bit uint 0x12345678
    # - an 32 bit signed int -0x1234
    # - an 64 bit signed int 0x12345678

    # The packing can also be applied to the word (wordorder) and bytes in each
    # word (byteorder)

    # The wordorder is applicable only for 32 and 64 bit values
    # Lets say we need to write a value 0x12345678 to a 32 bit register

    # The following combinations could be used to write the register

    # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #
    # Word Order - Big                      Byte Order - Big
    # word1 =0x1234 word2 = 0x5678

    # Word Order - Big                      Byte Order - Little
    # word1 =0x3412 word2 = 0x7856

    # Word Order - Little                   Byte Order - Big
    # word1 = 0x5678 word2 = 0x1234

    # Word Order - Little                   Byte Order - Little
    # word1 =0x7856 word2 = 0x3412
    # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #

    # ----------------------------------------------------------------------- #
    builder = BinaryPayloadBuilder(byteorder=Endian.Little,
                                   wordorder=Endian.Big)
    builder.add_string('abcdefgh')
    builder.add_32bit_float(22.34)
    builder.add_16bit_uint(0x1234)
    builder.add_16bit_uint(0x5678)
    builder.add_8bit_int(0x12)
    builder.add_bits([0, 1, 0, 1, 1, 0, 1, 0])
    builder.add_32bit_uint(0x12345678)
    builder.add_32bit_int(-0x1234)
    builder.add_64bit_int(0x1234567890ABCDEF)
    payload = builder.build()
    address = 0
    client.write_registers(address, payload, skip_encode=True, unit=1)
    # ----------------------------------------------------------------------- #
    # If you need to decode a collection of registers in a weird layout, the
    # payload decoder can help you as well.
    #
    # Here we demonstrate decoding a random register layout, unpacked it looks
    # like the following:
    #
    # - a 8 byte string 'abcdefgh'
    # - a 32 bit float 22.34
    # - a 16 bit unsigned int 0x1234
    # - another 16 bit unsigned int which we will ignore
    # - an 8 bit int 0x12
    # - an 8 bit bitstring [0,1,0,1,1,0,1,0]
    # ----------------------------------------------------------------------- #
    address = 0x00
    count = len(payload)
    result = client.read_holding_registers(address, count,  unit=1)
    print("-" * 60)
    print("Registers")
    print("-" * 60)
    print(result.registers)
    print("\n")
    decoder = BinaryPayloadDecoder.fromRegisters(result.registers,
                                                 byteorder=Endian.Little,
                                                 wordorder=Endian.Big)
    decoded = {
        'string': decoder.decode_string(8),
        'float': decoder.decode_32bit_float(),
        '16uint': decoder.decode_16bit_uint(),
        'ignored': decoder.skip_bytes(2),
        '8int': decoder.decode_8bit_int(),
        'bits': decoder.decode_bits(),
        "32uints": decoder.decode_32bit_uint(),
        "32ints": decoder.decode_32bit_int(),
        "64ints": decoder.decode_64bit_int(),
    }
    
    print("-" * 60)
    print("Decoded Data")
    print("-" * 60)
    for name, value in iteritems(decoded):
        print("%s\t" % name, hex(value) if isinstance(value, int) else value)
    
    # ----------------------------------------------------------------------- #
    # close the client
    # ----------------------------------------------------------------------- #
    client.close()
Example #45
0

	now = datetime.datetime.now()
	write_data("Starting data logger "+ now.strftime("%Y-%m-%d %H:%M")+"\n\n")

#	diris_modbus = ModbusClient(diris_host)
	diris_modbus = ModbusClient(method='rtu', port=diris_port, timeout=1, baudrate=9600, parity='E')
	diris_modbus.connect()



	while True:


		rk = diris_modbus.read_holding_registers(50536,2,unit=diris_slave_id)
		active_p = BinaryPayloadDecoder.fromRegisters(rk.registers,endian=Endian.Big).decode_32bit_uint()
		active_p = float(active_p)/100

		rk = diris_modbus.read_holding_registers(50538,2,unit=diris_slave_id)
		reactive_p = BinaryPayloadDecoder.fromRegisters(rk.registers,endian=Endian.Big).decode_32bit_uint()
		reactive_p = float(reactive_p)/100

		rk = diris_modbus.read_holding_registers(50540,2,unit=diris_slave_id)
		apparent_p = BinaryPayloadDecoder.fromRegisters(rk.registers,endian=Endian.Big).decode_32bit_uint()
		apparent_p = float(apparent_p)/100

#		decoder = BinaryPayloadDecoder.fromRegisters(rk.registers,endian=Endian.Big)
#		print decoder.decode_32bit_uint()


Example #46
0
    def update(self,client,Domoticz):
        value = "0"
        
        #Domoticz.Log("--> Device:"+self.device.Name+" Address="+str(self.UnitIdForIp)+", Register="+str(self.address)+", Function="+self.function+", Data type="+self.dataType+" Digits:"+str(self.digits)+" Method="+self.method)
        ###################################
        # pymodbus section
        ###################################
         
        if (self.method == "rtu" or self.method == "ascii" or self.method == "rtutcp"):
            Domoticz.Log("Start rtu read")
            
            try:
                # Which function to execute? RTU/ASCII/RTU over TCP or COM
                if (self.function == "1"): data = client.read_coils(self.address, self.registercount, unit=self.UnitIdForIpUnitIdForIp)
                elif (self.function == "2"): data = client.read_discrete_inputs(self.address, self.registercount, unit=self.UnitIdForIp)
                elif (self.function == "3"): data = client.read_holding_registers(self.address, self.registercount, unit=self.UnitIdForIp)
                elif (self.function == "4"): data = client.read_input_registers(self.address, self.registercount, unit=self.UnitIdForIp)
                else:
                    Domoticz.Debug("No function selected: " + str(self.function))
                    return
                Domoticz.Log("MODBUS DEBUG RESPONSE: " + str(data.registers))
            except Exception as e:
                Domoticz.Log("Modbus error communicating! (RTU/ASCII/RTU over TCP or COM), check your settings!"+repr(e))
                data = 0
                #self.device.Update(0, "0") # Update device to OFF in Domoticz

        ###################################
        # pymodbusTCP section
        ###################################
        else:  #if (self.method == "tcpip"):
            #Domoticz.Log("Start tcp read")
            
            try:
                # Which function to execute? TCP/IP
                if (function == "1"): data = client.read_coils(self.address, self.registercount)
                if (function == "2"): data = client.read_discrete_inputs(self.address, self.registercount)
                if (function == "3"): data = client.read_holding_registers(self.address, self.registercount)
                if (function == "4"): data = client.read_input_registers(self.address, self.registercount)
                Domoticz.Log("MODBUS DEBUG RESPONSE: " + str(data))
            except Exception as e:
                Domoticz.Log("Modbus error communicating! (TCP/IP), check your settings!"+repr(e))
                data = 0 
                #self.device.Update(0, "0") # Update device to OFF in Domoticz

        #Domoticz.Log("Modbus Na read" )
        
        if data:
            try:
                # How to decode the input?
                try:
                    decoder = BinaryPayloadDecoder.fromRegisters(data, byteorder=self.byteorder, wordorder=self.wordorder)
                except:            
                    decoder = BinaryPayloadDecoder.fromRegisters(data.registers, byteorder=self.byteorder, wordorder=self.wordorder)
            
                if (self.dataType == "noco"): value = data
                if (self.dataType == "int8LSB"):
                    ignored = decoder.skip_bytes(1)
                    value = decoder.decode_8bit_int()
                if (self.dataType == "int8MSB"): value = decoder.decode_8bit_int()
                if (self.dataType == "int16"): value = decoder.decode_16bit_int()
                if (self.dataType == "int16s"): value = decoder.decode_16bit_int()
                if (self.dataType == "int32"): value = decoder.decode_32bit_int()
                if (self.dataType == "int64"): value = decoder.decode_64bit_int()
                if (self.dataType == "uint8LSB"):
                    ignored = decoder.skip_bytes(1)
                    value = decoder.decode_8bit_uint()
                if (self.dataType == "uint8MSB"): value = decoder.decode_8bit_uint()   
                if (self.dataType == "uint16"): value = decoder.decode_16bit_uint()
                if (self.dataType == "uint32"): value = decoder.decode_32bit_uint()
                if (self.dataType == "uint64"): value = decoder.decode_64bit_uint()
                if (self.dataType == "float32"): value = decoder.decode_32bit_float()
                if (self.dataType == "float64"): value = decoder.decode_64bit_float()
                if (self.dataType == "string2"): value = decoder.decode_string(2)
                if (self.dataType == "string4"): value = decoder.decode_string(4)
                if (self.dataType == "string6"): value = decoder.decode_string(6)
                if (self.dataType == "string8"): value = decoder.decode_string(8)
                if (self.dataType == "bcd8"):
                    value=decoder.decoder.decode_8bit_int()
                    value=value & 0xf + value & (0xf0&0xf0>>4*10)
                if (self.dataType == "bcd16"):
                    value=decoder.decoder.decode_8bit_int()
                    value=value & 0xf + (value & 0xf0>>4*10) + (value & 0xf00>>8*100) + (value & 0xf000>>12*1000)
                if multiplydevice:
                   value=value*domoticz.device(multiplydevice)

                # Divide the value (decimal)?
                value = str(round(value / self.devide, self.digits))
                
                Domoticz.Log("MODBUS DEBUG VALUE: " + str(value)+" Old value:"+self.device.sValue+" Old value:"+str(self.device.nValue))
                #Domoticz.Log("LastUpdate:"+self.device.LastUpdate)
                
                age=(datetime.now()-datetime.strptime(self.device.LastUpdate, '%Y-%m-%d %H:%M:%S')).seconds
                
                #Domoticz.Log("LastUpdate seconds ago:"+str(age))
                if (self.device.sValue != value ) or age>300:
                    self.device.Update(0, value) # Update value in Domoticz
                    #Domoticz.Debug("Done update: " + str(value))
                    
                
            except Exception as e:
                Domoticz.Log("Modbus error decoding or received no data (TCP/IP)!, check your settings!"+repr(e))
                #self.device.Update(0, "0") # Update value in Domoticz
        else:       
            Domoticz.Log("No data")
                
    def decode_register(self, register, type):
        #omitting string for now since it requires a specified length

        if type == '8int':
            rr = self.read_register_raw(register, 1)
            decoder = BinaryPayloadDecoder.fromRegisters(
                rr.registers,
                byteorder=self.BYTE_ORDER,
                wordorder=self.WORD_ORDER)
            output = decoder.decode_8bit_int()

        elif type == '8uint':
            rr = self.read_register_raw(register, 1)
            decoder = BinaryPayloadDecoder.fromRegisters(
                rr.registers,
                byteorder=self.BYTE_ORDER,
                wordorder=self.WORD_ORDER)
            output = decoder.decode_8bit_uint()
        elif type == '16int':
            rr = self.read_register_raw(register, 1)
            decoder = BinaryPayloadDecoder.fromRegisters(
                rr.registers,
                byteorder=self.BYTE_ORDER,
                wordorder=self.WORD_ORDER)
            output = decoder.decode_16bit_int()
        elif type == '16uint':
            rr = self.read_register_raw(register, 1)
            decoder = BinaryPayloadDecoder.fromRegisters(
                rr.registers,
                byteorder=self.BYTE_ORDER,
                wordorder=self.WORD_ORDER)
            output = decoder.decode_16bit_uint()
        elif type == '32int':
            rr = self.read_register_raw(register, 2)
            decoder = BinaryPayloadDecoder.fromRegisters(
                rr.registers,
                byteorder=self.BYTE_ORDER,
                wordorder=self.WORD_ORDER)
            output = decoder.decode_32bit_int()
        elif type == '32uint':
            rr = self.read_register_raw(register, 2)
            decoder = BinaryPayloadDecoder.fromRegisters(
                rr.registers,
                byteorder=self.BYTE_ORDER,
                wordorder=self.WORD_ORDER)
            output = decoder.decode_32bit_uint()
        elif type == '32float':
            rr = self.read_register_raw(register, 2)
            decoder = BinaryPayloadDecoder.fromRegisters(
                rr.registers,
                byteorder=self.BYTE_ORDER,
                wordorder=self.WORD_ORDER)
            output = decoder.decode_32bit_float()
        elif type == '64int':
            rr = self.read_register_raw(register, 4)
            decoder = BinaryPayloadDecoder.fromRegisters(
                rr.registers,
                byteorder=self.BYTE_ORDER,
                wordorder=self.WORD_ORDER)
            output = decoder.decode_64bit_int()
        elif type == '64uint':
            rr = self.read_register_raw(register, 4)
            decoder = BinaryPayloadDecoder.fromRegisters(
                rr.registers,
                byteorder=self.BYTE_ORDER,
                wordorder=self.WORD_ORDER)
            output = decoder.decode_64bit_uint()
        elif type == 'ignore':
            rr = self.read_register_raw(register, 1)
            decoder = BinaryPayloadDecoder.fromRegisters(
                rr.registers,
                byteorder=self.BYTE_ORDER,
                wordorder=self.WORD_ORDER)
            output = decoder.skip_bytes(8)
        elif type == '64float':
            rr = self.read_register_raw(register, 4)
            decoder = BinaryPayloadDecoder.fromRegisters(
                rr.registers,
                byteorder=self.BYTE_ORDER,
                wordorder=self.WORD_ORDER)
            output = decoder.decode_64bit_float()

        return output
Example #48
0
 def convert(self, config, data):
     self.__result["telemetry"] = []
     self.__result["attributes"] = []
     for config_data in data:
         for tag in data[config_data]:
             try:
                 configuration = data[config_data][tag]["data_sent"]
                 response = data[config_data][tag]["input_data"]
                 if configuration.get("byteOrder"):
                     byte_order = configuration["byteOrder"]
                 elif config.get("byteOrder"):
                     byte_order = config["byteOrder"]
                 else:
                     byte_order = "LITTLE"
                 if configuration.get("wordOrder"):
                     word_order = configuration["wordOrder"]
                 elif config.get("wordOrder"):
                     word_order = config.get("wordOrder", "BIG")
                 else:
                     word_order = "BIG"
                 endian_order = Endian.Little if byte_order.upper(
                 ) == "LITTLE" else Endian.Big
                 word_endian_order = Endian.Little if word_order.upper(
                 ) == "LITTLE" else Endian.Big
                 decoded_data = None
                 if not isinstance(response,
                                   ModbusIOException) and not isinstance(
                                       response, ExceptionResponse):
                     if configuration["functionCode"] in [1, 2]:
                         result = response.bits
                         result = result if byte_order.upper(
                         ) == 'LITTLE' else result[::-1]
                         log.debug(result)
                         if configuration["type"].lower() == "bits":
                             decoded_data = result[:configuration.get(
                                 "objectsCount",
                                 configuration.
                                 get("registersCount",
                                     configuration.get("registerCount", 1)
                                     ))]
                             if len(decoded_data) == 1 and isinstance(
                                     decoded_data, list):
                                 decoded_data = decoded_data[0]
                         else:
                             decoded_data = result[0]
                     elif configuration["functionCode"] in [3, 4]:
                         decoder = None
                         registers = response.registers
                         log.debug("Tag: %s Config: %s registers: %s", tag,
                                   str(configuration), str(registers))
                         try:
                             decoder = BinaryPayloadDecoder.fromRegisters(
                                 registers,
                                 byteorder=endian_order,
                                 wordorder=word_endian_order)
                         except TypeError:
                             # pylint: disable=E1123
                             decoder = BinaryPayloadDecoder.fromRegisters(
                                 registers,
                                 endian=endian_order,
                                 wordorder=word_endian_order)
                         assert decoder is not None
                         decoded_data = self.__decode_from_registers(
                             decoder, configuration)
                         if configuration.get("divider"):
                             decoded_data = float(decoded_data) / float(
                                 configuration["divider"])
                         if configuration.get("multiplier"):
                             decoded_data = decoded_data * configuration[
                                 "multiplier"]
                 else:
                     log.exception(response)
                     decoded_data = None
                 if config_data == "rpc":
                     return decoded_data
                 log.debug("datatype: %s \t key: %s \t value: %s",
                           self.__datatypes[config_data], tag,
                           str(decoded_data))
                 self.__result[self.__datatypes[config_data]].append(
                     {tag: decoded_data})
             except Exception as e:
                 log.exception(e)
     log.debug(self.__result)
     return self.__result
Example #49
0
def updating_writer(a):
    ''' A worker process that runs every so often and
    updates live values of the context. It should be noted
    that there is a race condition for the update.

    :param arguments: The input arguments to the call
    '''
    global g_Time
    global s_Time
    global g_increment

    if g_Time >= 60*20:
        g_Time = 0
        log.debug("g_Time reset")
        print "g_Time reset"

    g_Time += 1

    log.debug("updating the context at {0}".format(g_Time))
    context  = a[0]
    srv_id = a[1]
    register = 3
    slave_id = 0x00
    # gets current values
    if context[slave_id].zero_mode:
        START_ADDRESS = FIRST_REGISTER   # if zero_mode=True
    else:
        START_ADDRESS = FIRST_REGISTER-1 # if zero_mode=False. inizia a leggere da 40000 e prendi gli N successivi,escluso il 40000
    values   = context[slave_id].getValues(register, START_ADDRESS, count=NUM_REGISTERS)
    # update P and Q with random values
    log.debug("pump context values: " + str(values))


    decoder = BinaryPayloadDecoder.fromRegisters(values[502:503],endian=Endian.Little)
    bits_502 = decoder.decode_bits()
    bits_502 += decoder.decode_bits()
    decoder = BinaryPayloadDecoder.fromRegisters(values[552:553],endian=Endian.Little)
    bits_552 = decoder.decode_bits()
    bits_552 += decoder.decode_bits()
    decoder = BinaryPayloadDecoder.fromRegisters(values[506:507],endian=Endian.Little)
    bits_506 = decoder.decode_bits()
    bits_506 += decoder.decode_bits()

    if g_Time >= s_Time > 0:
        print "start iniettore dopo {0} secondi".format(s_Time)
        log.debug("start iniettore dopo {0} secondi".format(s_Time))
        s_Time = 0
        bits_502[7] = 1 # START INIETTORE
        bits_builder = BinaryPayloadBuilder(endian=Endian.Little)
        bits_builder.add_bits(bits_502)
        bits_reg=bits_builder.to_registers()
        values[502:503]=[bits_reg[0]]

    cicli_min = 0
    p_new = 0
    # if iniettore Started
    if bits_502[7]:
        s_Time = 0
        #cicli_min = cicli_rand.rvs()
        cicli_min = int( out_val_q(g_Time,50.) )
        p_new = int(out_val_p(g_Time,values[560])) + delta_rand.rvs() + 1
        if p_new < 1:
            cicli_min = 70.
        else:
            cicli_min = 70./p_new
        
        if g_Time % 13 == 0:
            g_increment += 1
        p_new = p_new + g_increment
        
        ##########################################
        ### Verifica limite massimo P
        #############################
        if p_new >= values[560]:            
            log.debug("PMax exceeded: %d (516) > %d (560)" % (p_new,values[560]) )
            p_new = values[560] + delta_rand.rvs() + 1
            
        ##########################################
        ### Verifica limite massimo Q
        #############################
        if cicli_min >= values[562]:
            log.debug("QMax exceeded: %d (520) > %d (562)" % (cicli_min,values[562]) )
            cicli_min = values[562]
        else:
            if values[560] == 0:
                print "560 è zero"
                values[560] = 1
            if p_new/values[560] >= 0.5:
                cicli_min = max(1,int((values[560])/max(1,p_new)))
            else:
                cicli_min = 3*values[560]/max(1,p_new)        
        
    else:  
        cicli_min = 0
        p_new = 0

    log.debug("p_new=%d" % p_new)
    
    q_val = cicli_min*liters_cycle
    q_m_ch = 60.0*q_val/1000.0
    log.debug("cicli=%d, q=%f, mc=%f" % (cicli_min, q_val,q_m_ch))
    # conversione float - Endian.Little il primo è il meno significativo
    if p_new < 0:
        p_new = 0
        
    if cicli_min < 0:
        cicli_min = 0
    values[516] = p_new # %MW516 PRESSIONE ATTUALE
    values[520] = cicli_min
    builder = BinaryPayloadBuilder(endian=Endian.Little)
    builder.add_32bit_float(q_val)
    builder.add_32bit_float(q_m_ch)
    reg=builder.to_registers()
    log.debug("2 x 32bit_float = %s" % str(reg))
    values[522:526]=reg

    log.debug("On Pump Server %02d new values (516-525): %s" % (srv_id, str(values[516:526])))

    # assign new values to context
    values[599] = 699
    context[slave_id].setValues(register, START_ADDRESS, values)
    def _decode_response(
        resp: ReadCoilsResponse
        | ReadDiscreteInputsResponse
        | ReadHoldingRegistersResponse
        | ReadInputRegistersResponse,
        obj: ModbusObj,
    ) -> bool | int | float:
        """Decodes value from registers and scale them.
        # TODO make 4 decoders for all combinations in bo, wo and use them?
        Args:
            resp: Read request response.
            obj: Object instance

        Returns:
            Decoded from register\bits and scaled value.
        """

        # TODO: Add decode with different byteorder in bytes VisioDecoder class

        if isinstance(resp, ReadBitsResponseBase):
            data = resp.bits
            return 1 if data[0] else 0  # TODO: add support several bits?
        if isinstance(resp, ReadRegistersResponseBase):
            data = resp.registers
            scaled: float | int
            if obj.data_type == ModbusDataType.BOOL:
                if obj.bit and obj.data_length == 1:
                    value = format(data[0], "0>16b")
                    value = list(reversed(value))[obj.bit]
                    scaled = decoded = int(value)
                elif obj.data_length == 1:
                    scaled = decoded = 1 if data[0] else 0
                else:
                    scaled = decoded = any(data)
            else:
                decoder = BinaryPayloadDecoder.fromRegisters(
                    registers=data, byteorder=obj.byte_order, wordorder=obj.word_order
                )
                decode_funcs = {
                    ModbusDataType.BITS: decoder.decode_bits,
                    # DataType.BOOL: None,
                    # DataType.STR: decoder.decode_string,
                    8: {
                        ModbusDataType.INT: decoder.decode_8bit_int,
                        ModbusDataType.UINT: decoder.decode_8bit_uint,
                    },
                    16: {
                        ModbusDataType.INT: decoder.decode_16bit_int,
                        ModbusDataType.UINT: decoder.decode_16bit_uint,
                        ModbusDataType.FLOAT: decoder.decode_16bit_float,
                        # DataType.BOOL: None,
                    },
                    32: {
                        ModbusDataType.INT: decoder.decode_32bit_int,
                        ModbusDataType.UINT: decoder.decode_32bit_uint,
                        ModbusDataType.FLOAT: decoder.decode_32bit_float,
                    },
                    64: {
                        ModbusDataType.INT: decoder.decode_64bit_int,
                        ModbusDataType.UINT: decoder.decode_64bit_uint,
                        ModbusDataType.FLOAT: decoder.decode_64bit_float,
                    },
                }
                assert decode_funcs[obj.data_length][obj.data_type] is not None

                decoded = decode_funcs[obj.data_length][obj.data_type]()
                scaled = decoded * obj.scale + obj.offset  # Scaling
            _LOG.debug(
                "Decoded",
                extra={
                    "object": obj,
                    "value_raw": data,
                    "value_decoded": decoded,
                    "value_scaled": scaled,
                },
            )
            return scaled
        raise NotImplementedError
 def _convert_to_float(self, registers):
     """ Converts unsigned int from Modbus device to a floating point number """
     decoder = BinaryPayloadDecoder.fromRegisters(registers,
                                                  byteorder=Endian.Big,
                                                  wordorder=Endian.Big)
     return round(decoder.decode_32bit_float(), 2)
Example #52
0
def main():
    # IP = input("Slave IP: ")
    # ID = input("Slave ID: ")
    IP = "192.168.0.13"
    ID = 2

    client = ModbusCLient(IP, port=502)

    if client.connect() == False:
        debug.error("Unable to connect to PLC")
        return
    while True:

        payload = client.read_holding_registers(0, 1, unit=ID)
        # print(payload.bits)

        decoder = BinaryPayloadDecoder.fromRegisters(payload.registers,
                                                     byteorder=Endian.Little,
                                                     wordorder=Endian.Big)
        port_0 = decoder.decode_bits()

        payload = client.read_holding_registers(1, 1, unit=ID)

        decoder = BinaryPayloadDecoder.fromRegisters(payload.registers,
                                                     byteorder=Endian.Big,
                                                     wordorder=Endian.Little)
        port_1 = decoder.decode_bits()

        debug.info("Input 0: {}".format(port_0))
        q_0 = port_0[0]
        debug.debug(q_0)
        debug.info("Input 1: {}".format(port_1))

        # decoded = OrderedDict([
        # ('Port_0', decoder.decode_bits()),
        # ('Port_1', decoder.decode_bits()),
        # # # ('Analog_1', decoder.decode_32bit_int()),
        # # # ('Analog_2', decoder.decode_16bit_int()),
        # ])
        #
        # for name,value in iteritems(decoded):
        #     debug.info("{}: {}\t".format(name,value))
        # print("vida: {}".format(decoder.decode_bits()))
        # print(payload.registers)
        # print("Bits: {}".format(decoder.decode_bits(1)))

        payload = client.read_holding_registers(2, 2, unit=ID)

        debug.debug("Payload: {} {}".format(payload.getRegister(0),
                                            payload.getRegister(1)))

        # decoder = BinaryPayloadDecoder.fromRegisters(payload.registers,
        #                                                 byteorder = Endian.Little,
        #                                                 wordorder = Endian.Little)
        # decoded = OrderedDict([
        # # ('Port_0', decoder.decode_bits()),
        # # ('Port_1', decoder.decode_bits()),
        # ('Analog_1', decoder.decode_16bit_int()),
        # ('Analog_2', decoder.decode_16bit_int()),
        # ])
        #
        #

        sleep(10)

        builder = BinaryPayloadBuilder(byteorder=Endian.Big,
                                       wordorder=Endian.Little)

        builder.add_bits([1, 1, 0, 0, 0, 0, 1, 0])

        payload = builder.to_registers()

        debug.debug(payload)

        client.write_registers(4, payload, unit=ID)
Example #53
0
 def decodeData(self,data):
     returnData = [0]*(len(data)/2)
     decoder = BinaryPayloadDecoder.fromRegisters(data, endian=Endian.Little)
     for i in range(0,len(data)/2):
         returnData[i] = round(decoder.decode_32bit_float(),2)
     return returnData
Example #54
0
import binascii
from pymodbus.constants import Endian
from pymodbus.payload import BinaryPayloadDecoder
ipaddress = str(sys.argv[1])
from pymodbus.client.sync import ModbusTcpClient
client = ModbusTcpClient(ipaddress, port=502)
connection = client.connect()

# Studer Battery Power
request = client.read_input_registers(6, 2, unit=60)
if request.isError():
    # handle error, log?
    print('Modbus Error:', request)
else:
    result = request.registers
decoder = BinaryPayloadDecoder.fromRegisters(result, byteorder=Endian.Big)
bw = decoder.decode_32bit_float()  # type: float
f = open('/var/www/html/openWB/ramdisk/speicherleistung', 'w')
f.write(str(bw))
f.close()

# Studer SOC
request = client.read_input_registers(4, 2, unit=60)
if request.isError():
    # handle error, log?
    print('Modbus Error:', request)
else:
    result = request.registers
decoder = BinaryPayloadDecoder.fromRegisters(result, byteorder=Endian.Big)
bs = decoder.decode_32bit_float()  # type: float
f = open('/var/www/html/openWB/ramdisk/speichersoc', 'w')
    def read(self):
        """ Read registers from client"""
        if pymodbus_found:
            time.sleep(float(self._settings["interval"]))
            f = []
            c = Cargo.new_cargo(rawdata="")
            # valid datacodes list and number of registers associated
            # in modbus protocol, one register is 16 bits or 2 bytes
            valid_datacodes = ({
                'h': 1,
                'H': 1,
                'i': 2,
                'l': 2,
                'I': 2,
                'L': 2,
                'f': 2,
                'q': 4,
                'Q': 4,
                'd': 4
            })

            if not self._modcon:
                self._con.close()
                self._log.info("Not connected, retrying connect %s",
                               self.init_settings)
                self._con = self._open_modTCP(
                    self.init_settings["modbus_IP"],
                    self.init_settings["modbus_port"])

            if self._modcon:
                # fetch nodeid
                if 'nodeId' in self._settings:
                    node = str(self._settings["nodeId"])
                else:
                    self._log.error("please provide a nodeId")
                    return

                # stores registers
                if 'register' in self._settings:
                    registers = self._settings["register"]
                else:
                    self._log.error(
                        "please provide a register number or a list of registers"
                    )
                    return

                # fetch unitids if present
                UnitIds = self._settings.get("nUnit", None)

                # stores names
                # fetch datacode or datacodes
                if node in ehc.nodelist and 'rx' in ehc.nodelist[node]:
                    rNames = ehc.nodelist[node]['rx']['names']
                    if 'datacode' in ehc.nodelist[node]['rx']:
                        datacode = ehc.nodelist[node]['rx']['datacode']
                        datacodes = None
                    elif 'datacodes' in ehc.nodelist[node]['rx']:
                        datacodes = ehc.nodelist[node]['rx']['datacodes']
                    else:
                        self._log.error(
                            "please provide a datacode or a list of datacodes")
                        return

                # check if number of registers and number of names are the same
                if len(rNames) != len(registers):
                    self._log.error(
                        "You have to define an equal number of registers and of names"
                    )
                    return
                # check if number of names and number of datacodes are the same
                if datacodes is not None:
                    if len(datacodes) != len(rNames):
                        self._log.error(
                            "You are using datacodes. You have to define an equal number of datacodes and of names"
                        )
                        return

                # calculate expected size in bytes and search for invalid datacode(s)
                expectedSize = 0
                if datacodes is not None:
                    for code in datacodes:
                        if code not in valid_datacodes:
                            self._log.debug("-" * 46)
                            self._log.debug("invalid datacode")
                            self._log.debug("-" * 46)
                            return
                        else:
                            expectedSize += valid_datacodes[code] * 2
                else:
                    if datacode not in valid_datacodes:
                        self._log.debug("-" * 46)
                        self._log.debug("invalid datacode")
                        self._log.debug("-" * 46)
                        return
                    else:
                        expectedSize = len(
                            rNames) * valid_datacodes[datacode] * 2

                self._log.debug("expected bytes number after encoding: %s",
                                expectedSize)

                # at this stage, we don't have any invalid datacode(s)
                # so we can loop and read registers
                for idx, rName in enumerate(rNames):
                    register = int(registers[idx], 0)
                    if UnitIds is not None:
                        unitId = int(UnitIds[idx])
                    else:
                        unitId = 1
                    if datacodes is not None:
                        datacode = datacodes[idx]

                    self._log.debug("datacode %s", datacode)
                    qty = valid_datacodes[datacode]
                    self._log.debug(
                        "reading register #: %s, qty #: %s, unit #: %s",
                        register, qty, unitId)

                    try:
                        self.rVal = self._con.read_input_registers(
                            address=register, count=qty, unit=unitId)
                    #    assert self.rVal.function_code < 0x80
                    except Exception as e:
                        self._log.error(
                            "Connection failed on read of register: %s : %s",
                            register, e)
                        self._modcon = False
                        #missing datas will lead to an incorrect encoding
                        #we have to drop the payload
                        return
                    else:
                        #self._log.debug("register value: %s type= %s", self.rVal.registers, type(self.rVal.registers))
                        #f = f + self.rVal.registers
                        decoder = BinaryPayloadDecoder.fromRegisters(
                            self.rVal.registers,
                            byteorder=Endian.Big,
                            wordorder=Endian.Big)
                        if datacode == 'h':
                            rValD = decoder.decode_16bit_int()
                        elif datacode == 'H':
                            rValD = decoder.decode_16bit_uint()
                        elif datacode == 'i':
                            rValD = decoder.decode_32bit_int()
                        elif datacode == 'l':
                            rValD = decoder.decode_32bit_int()
                        elif datacode == 'I':
                            rValD = decoder.decode_32bit_uint()
                        elif datacode == 'L':
                            rValD = decoder.decode_32bit_uint()
                        elif datacode == 'f':
                            rValD = decoder.decode_32bit_float() * 10
                        elif datacode == 'q':
                            rValD = decoder.decode_64bit_int()
                        elif datacode == 'Q':
                            rValD = decoder.decode_64bit_uint()
                        elif datacode == 'd':
                            rValD = decoder.decode_64bit_float() * 10

                        t = ehc.encode(datacode, rValD)
                        f = f + list(t)
                        self._log.debug("Encoded value: %s", t)
                        self._log.debug("value: %s", rValD)

                #test if payload length is OK
                if len(f) == expectedSize:
                    self._log.debug("payload size OK (%d)", len(f))
                    self._log.debug("reporting data: %s", f)
                    c.nodeid = node
                    c.realdata = f
                    self._log.debug("Return from read data: %s", c.realdata)
                    return c
                else:
                    self._log.error("incorrect payload size: %d expecting %d",
                                    len(f), expectedSize)
Example #56
0
                 CU_Pf,CU_Pr,CU_Pt,CU_V,
                 BH_Pf,BH_Pr,BH_Pt,
                 HV_Bias, HV_Off_Setpoint,HV_On_Setpoint,
                 SRF_Pf,SRF_Pr,SRF_Pt,
                 Pulse_Freq,Pulse_Duty,Pulse_Delay,IR_Temp,Current_Emitted]

#Building the list of tags to grab
DBA_Mag_Tags = Hnums + Vnums + Dpnums + Solnums + CU_Tags + BH_Tags + HV_Tags + SRF_Tags + Pulse_Tags

client = ModbusTcpClient('10.6.0.2')
p = 0
N = 1
temp_list = []
for j in range(len(DBA_Mag_Names)):
    result = client.read_holding_registers(int(DBA_Mag_Tags[j]),2,unit=1)
    number = BinaryPayloadDecoder.fromRegisters(result.registers, byteorder=Endian.Big, wordorder=Endian.Big)
    temp_list.append(round(number.decode_32bit_float(),3))

    time.sleep(.020)
client.close()

WFH_1,WFH_2,WFH_3,WFH_4,WFH_5,WFH_6,WFH_7,WFH_8,WFH_9,WFH_10,WFH_11,WFH_12,WFH_13,WFH_14,WFH_15,WFH_16,WFH_17,WFH_18,WFH_19,WFH_20,WFH_21,WFV_1,WFV_2,WFV_3,WFV_4,WFV_5,WFV_6,WFV_7,WFV_8,WFV_9,WFV_10,WFV_11,WFV_12,WFV_13,WFV_14,WFV_15,WFV_16,WFV_17,WFV_18,WFV_19,WFV_20,WFV_21,DP_1,DP_2,DP_3,DP_4,DP_5,DP_6,DP_7,DP_8,Sol_1,Sol_2,Sol_3,Sol_4,Sol_5,Sol_6,Sol_7,Sol_8,Sol_9,CU_Pf,CU_Pr,CU_Pt,CU_V,BH_Pf,BH_Pr,BH_Pt,HV_Bias,HV_Off_Setpoint,HV_On_Setpoint,SRF_Pf,SRF_Pr,SRF_Pt,Pulse_Freq,Pulse_Duty,Pulse_Delay,IR_Temp,Current_Emitted = temp_list

#Putting the dataframe into an excel file.
##########################################

#into the spreadsheet format
dftoexcel = pd.DataFrame([[WFV_1,WFH_1,Sol_1,DP_1,'','Cu Gun (1)',CU_Pf,CU_Pr,CU_Pt,CU_V,'','','','','','','','','',''],
                       [WFV_2,WFH_2,Sol_2,DP_2,'','BH (2)',BH_Pf,BH_Pr,BH_Pt,BH_V,'','','','','','','','','',''],
                       [WFV_3,WFH_3,Sol_3,DP_3,'','Bias (0)','--','--','--',HV_Bias,'','','','','','','','','',''],
                       [WFV_4,WFH_4,Sol_4,DP_4,'','SRF',SRF_Pf,SRF_Pr,SRF_Pt,'','','','','','','','','','',''],
Example #57
0
# implementations differentiate holding/input discrete/coils and as such
# you will not be able to write to these, therefore the starting values
# are not known to these tests. Furthermore, some use the same memory
# blocks for the two sets, so a change to one is a change to the other.
# Keep both of these cases in mind when testing as the following will
# _only_ pass with the supplied async modbus server (script supplied).
#---------------------------------------------------------------------------# 
#rr = client.read_holding_registers(1,1)
#
#rr = client.read_holding_registers(address=0xF900, count=1)
#decoder = BcdPayloadDecoder.fromRegisters(rr.registers)
#Time_Interval = decoder.decode_int(2)
#Time_Interval = rs485.read_string(0xF900, functioncode=3, numberOfRegisters=2)[0]
#
rr = client.read_input_registers(address=0x0000, count=2)
decoder = BinaryPayloadDecoder.fromRegisters(rr.registers, endian=Endian.Big)
Volts = decoder.decode_32bit_float()
#
rr = client.read_input_registers(address=0x0006, count=2)
decoder = BinaryPayloadDecoder.fromRegisters(rr.registers, endian=Endian.Big)
Current = decoder.decode_32bit_float()
#
rr = client.read_input_registers(address=0x000C, count=2)
decoder = BinaryPayloadDecoder.fromRegisters(rr.registers, endian=Endian.Big)
Active_Power = decoder.decode_32bit_float()
#
rr = client.read_input_registers(address=0x0012, count=2)
decoder = BinaryPayloadDecoder.fromRegisters(rr.registers, endian=Endian.Big)
Apparent_Power = decoder.decode_32bit_float()
#
rr = client.read_input_registers(address=0x0018, count=2)
Example #58
0
    def run(self):
        global OUTPUT
        ret = dict()

        modbus_server = cfg.get("sensors", "server")
        modbus_port = int(cfg.get("sensors", "port")) 
        self.client = ModbusClient(modbus_server, port=modbus_port)

        temp_reg = int(cfg.get("sensors", "temperature_reg"),16)
        humid_reg = int(cfg.get("sensors", "humidity_reg"), 16)
        pressure_reg = int(cfg.get("sensors", "pressure_reg"), 16)
        geo_lat_reg = int(cfg.get("sensors", "geo_latitude_reg"), 16)
        geo_long_reg = int(cfg.get("sensors", "geo_longitude_reg"), 16) 
        key_op_reg = int(cfg.get("sensors", "key_operation_reg"), 16)
 
        poll_freq = int(cfg.get("sensors", "poll_frequency"))

        while True:
            if self.stop_event.is_set():
                break
            try:
                try:
                    # Read all data in a single go
		    # recv = self.client.read_holding_registers(temp_reg,5)

                    # Read Temperature 
                    recv = self.client.read_holding_registers(temp_reg,1)
                    ret['Temperature'] = recv.registers[0]

                    # Read Humidity
                    recv = self.client.read_holding_registers(humid_reg,1)
                    ret['Humidity'] = recv.registers[0]

                    # Read Pressure
                    recv = self.client.read_holding_registers(pressure_reg,1)     
                    ret['Pressure'] = recv.registers[0]

                    # Read Geo location latitude
                    recv = self.client.read_holding_registers(geo_lat_reg,2)
                    decoder = BinaryPayloadDecoder.fromRegisters(recv.registers, endian=Endian.Big)
                    ret['Latitude'] = decoder.decode_32bit_float() 
 
                    # Read Geo location longitude
                    recv = self.client.read_holding_registers(geo_long_reg,2)
                    decoder = BinaryPayloadDecoder.fromRegisters(recv.registers, endian=Endian.Big)
                    ret['Longitude'] = decoder.decode_32bit_float()
 
                    # Read keyboard operation
                    recv = self.client.read_holding_registers(key_op_reg,6)
                    decoder = BinaryPayloadDecoder.fromRegisters(recv.registers, endian=Endian.Big)
                    reg_str = decoder.decode_string(6)
                    str_tokens = reg_str.split("\x00")
                    ret['Key'] = str_tokens[0]
                     
                except ModbusException:
                    logger.error("Failed to retrieve data from modbus server!")

                OUTPUT = ret
                dweet(ret)
                send_to_cloud(ret)
                logger.debug("###################################")
                time.sleep(poll_freq)
            except Exception as ex:
                logger.exception("Exception.. but let us be resilient..")
                time.sleep(poll_freq)
Example #59
0
# If you need to decode a collection of registers in a weird layout, the
# payload decoder can help you as well.
#
# Here we demonstrate decoding a random register layout, unpacked it looks
# like the following:
#
# - a 8 byte string 'abcdefgh'
# - a 32 bit float 22.34
# - a 16 bit unsigned int 0x1234
# - an 8 bit int 0x12
# - an 8 bit bitstring [0,1,0,1,1,0,1,0]
# ---------------------------------------------------------------------------#
address = 0x01
count = 8
result = client.read_input_registers(address, count)
decoder = BinaryPayloadDecoder.fromRegisters(result.registers, endian=Endian.Little)
decoded = {
    "string": decoder.decode_string(8),
    "float": decoder.decode_32bit_float(),
    "16uint": decoder.decode_16bit_uint(),
    "8int": decoder.decode_8bit_int(),
    "bits": decoder.decode_bits(),
}

print "-" * 60
print "Decoded Data"
print "-" * 60
for name, value in decoded.iteritems():
    print ("%s\t" % name), value

# ---------------------------------------------------------------------------#
Example #60
0
    def convert_format(self, block_start, block_end, data, sections, start, query_length):
    #def convert_format(self, data, sections, start, query_length):
        values = dict()
        ptr = 0
        if sections[0][7] == 'BB':
            decoder = BinaryPayloadDecoder.fromRegisters(data,
                                                        byteorder=Endian.Big,
                                                        wordorder=Endian.Big)
        elif sections[0][7] == 'BL':                                                        
            decoder = BinaryPayloadDecoder.fromRegisters(data,
                                                    byteorder=Endian.Big,
                                                    wordorder=Endian.Little)
        for s in sections:
            if block_start + ptr >= start and block_start + ptr < start + query_length:
                #print("DECODE:", ptr, s[0], start , query_length, s)
                if s[0] == "uint16":
                    if s[2] == 1:
                        val = decoder.decode_16bit_uint() * int(s[2]) + int(s[3])
                    else:    
                        val = decoder.decode_16bit_uint() * float(s[2]) + float(s[3])
                elif s[0] in ["sint16", "int16"]:
                    if s[2] == 1:
                        val = decoder.decode_16bit_int() * int(s[2]) + int(s[3])
                    else:
                        val = decoder.decode_16bit_int() * float(s[2]) + float(s[3])
                elif s[0] == "uint32":
                    val = decoder.decode_32bit_uint() * float(s[2]) + float(s[3])
                elif s[0] in ["sint32", "int32"]:
                    val = decoder.decode_32bit_int() * float(s[2]) + float(s[3])
                elif s[0] == "float32":
                    val = decoder.decode_32bit_float() * float(s[2]) + float(s[3])
                elif s[0] == "bit16":
                    d_1 = decoder.decode_bits()
                    d_2 = decoder.decode_bits()
                    val = d_1 + d_2
                    #print(d_1, d_2, val)
                elif s[0][:3] == "str":
                    length = int(s[1])
                    val1 = decoder.decode_string(length)
                    #print("String Received", s, val1)
                    val = val1.decode()
                else:
                    print("Unknown type", s)
                #print(ptr, s, val )
                ## ***** ROHIT change it to format
                field_name = self.params["field_name"].format(source=s[4], block=s[5], field=s[6] )
                values[field_name]  = val 

            if s[0] in [ "bit16", "uint16", "sint16", "int16"]:
                ptr+=1
            elif s[0] in ["uint32", "sint32", "int32", "float32"] :
                ptr +=2
            elif s[0][:3] == "str":
                length = int(s[1])
                ptr += length/2
            else:
                print("Unknown type", s)

            #print(ptr, s, val )
        #print("Formated Values", values)
        return values