Пример #1
0
def read_sensors(request):
    sensors = Sensor.objects.all()
    sensor_data = []
    dictionary = {}
    for sensor in sensors:
        client = ModbusTcpClient(sensor.address.server, port=502, timeout=1)
        try:
            client.connect()
            if sensor.sensor_type == Sensor.SensorType.DIGITAL:
                reply = client.read_discrete_inputs(sensor.channel, 1, unit=1)
                sensor_reading = reply.bits[0]
                sensor_response = {
                    'sensor_name': sensor.name,
                    'sensor_reading': sensor_reading
                }
                if sensor.digital_sensor_alert and sensor.email and str(
                        sensor_reading) != sensor.last_value:
                    if sensor.digital_alert_value and sensor_reading:
                        send_sensor_alert_email(sensor, str(sensor_reading))
                        #send_sensor_alert_email()
                    elif not sensor.digital_alert_value and not sensor_reading:
                        send_sensor_alert_email(sensor, str(sensor_reading))
                        #send_sensor_alert_email()
            else:
                reply = client.read_input_registers(sensor.channel, 1, unit=1)
                sensor_reading = round(
                    reply.registers[0] * sensor.conversion_factor, 2)
                if sensor.high_alert_value and sensor.email:
                    if sensor_reading > sensor.high_alert_value and float(
                            sensor.last_value) <= sensor.high_alert_value:
                        send_sensor_alert_email(sensor, str(sensor_reading))
                        #send_sensor_alert_email()
                if sensor.low_alert_value and sensor.email:
                    if sensor_reading < sensor.low_alert_value and float(
                            sensor.last_value) >= sensor.low_alert_value:
                        send_sensor_alert_email(sensor, str(sensor_reading))
                        #send_sensor_alert_email()
            sensor.last_value = str(sensor_reading)
            sensor.save()
            client.close()
        except:
            sensor_reading = "Could Not Connect"
        sensor_response = {
            'sensor_name': sensor.name,
            'sensor_reading': sensor_reading
        }
        sensor_data.append(sensor_response)
        client.close()
    dictionary['sensor_data'] = sensor_data
    return render(request, 'sensors/sensor_data.html', dictionary)
Пример #2
0
class MBPLC(PLC):
    """PLC con comunicación Modbus.

    Args:
    address (str): Dirección IP (o nombre) del controlador.
    port (int): Puerto de conexión. Típicamente el 502.
    unit (int): Número de esclavo.
    method (str): Método de conexión (RTU/ASCII)
    retries (int): Reintentos de lectura/escritura.
    client (ModbusClient): Cliente modbus.
    pollingtime (float): Segundos entre escaneos.

    Attributes:
    coil (Memory): Memoria de bobinas.
    input (Memory): Memoria de entradas digitales.
    holding (Memory): Memoria de registros de retención.
    register  (Memory): Memoria de registros de entrada.
    client (ModbusClient): Cliente Modbus.
    thread (Thread): Hebra de escaneo.
    
    """

    class COIL:
        """Tipo de memoria COIL."""
        pass
    class INPUT:
        """Tipo de memoria INPUT."""
        pass
    class HOLDING:
        """Tipo de memoria HOLDING."""
        pass
    class REGISTER:
        """Tipo de memoria REGISTER."""
        pass


    class Memory(PLC.Memory):
        ''' Representacióne un área de memoria.

        Args:
        plc (PLC): Controlador al que pertenece.
        memorytype (type): Tipo de memoria (COIL, INPUT, HOLDING, REGISTER).

        Attributes:
        minindex (int): Dirección más baja de la memoria leída.
        maxindex (int): Dirección más alta de la memoria leída.

        '''

        class Tag(PLC.Memory.Tag):
            ''' Variable de controlador Modbus.

            Args:
            memory (Memory): Memoria a la que pertenece.
            key (str): Nombre.
            description (str): Descripción.
            address: Dirección (None si no esta asociada).
            
            Attributes:
            value: Valor.
            subscriptor (Subcriptor[]): Objetos suscritos a los cambios.
            
            '''

            def __init__(self, memory:PLC.Memory, key:str, description:str="", address=None):
                if type(address)==str:
                    address=int(address)
                super().__init__(memory,key,description,address)
                if memory.minindex is None or memory.minindex>address:
                    memory.minindex=address
                if memory.maxindex is None or memory.maxindex<address:
                    memory.maxindex=address
                
            def set(self, value):
                ''' Modifica el valor de una variable.

                Args:
                value: Nuevo valor de la variable.

                '''

                plc=self.memory.plc
                if plc.connected:
                    try:
                        if self.memory.memorytype==MBPLC.COIL:
                            if isinstance(value,str):
                                if value.upper()=="TRUE" or value=="1":
                                    value=True
                                elif value.upper()=="FALSE" or value=="0":
                                    value=False
                            rw = plc.client.write_coil(self.address,value,unit=plc.unit)
                        if self.memory.memorytype==MBPLC.HOLDING:
                            if isinstance(value,str):
                                value=int(value)
                            rw = plc.client.write_register(self.address,value,unit=plc.unit)
                        self.update(value)
                    except Exception as e:
                        self.memory.plc.connected=False
                        printexception(e,"Error writing to PLC")
                        

                
        def __init__(self, plc:PLC, memorytype:type):
            self.memorytype=memorytype
            self.minindex=None
            self.maxindex=None
            super().__init__(plc)
    

    def __init__(self, address:str, port:int=502, unit:int=1, method:str="rtu", retries:int=3, pollingtime:float=1.0):
        super().__init__()
        self.coil=self.create("coil",MBPLC.COIL)
        self.input=self.create("input",MBPLC.INPUT)
        self.holding=self.create("holding",MBPLC.HOLDING)
        self.register=self.create("register",MBPLC.REGISTER)
        self.address=address
        self.unit=unit
        self.port=port
        self.method=method
        self.retries=retries
        self.pollingtime=pollingtime
        self.client = ModbusClient(address, port, method=method, retries=retries)
        self.thread=Thread(target=self.__Polling, args=())

    def create(self,memory_key, memorytype:type):
        ''' Crea una memoria en el controlador.

        Args:
        memory_key (str): Nombre o identificador de la memoria.
        memorytype (type): Tipo de memoria (COIL, INPUT, HOLDING, REGISTER).

        Returns (Memory):
        Memoria que se ha creado.
        
        ''' 
        return self.set(memory_key, self.Memory(self, memorytype))

    def connect(self):
        ''' Conexión con el controlador

        '''
        self.thread.start()

    def disconnect(self):
        ''' Termina la conexión con el controlador.

        ''' 
        self.connected=false
        self.client.close()

    def read(self):
        ''' Lectura de un área de memoria del controlador real.

        Si falla la lectura (tras el número de reintentos)
        se actualiza el estado de conexión a desconectado.

        '''
        try:
            if not self.coil.minindex is None:
                rr = self.client.read_coils(self.coil.minindex, self.coil.maxindex-self.coil.minindex+1,unit=self.unit)
                for i in range(self.coil.minindex,self.coil.maxindex+1):
                    if i in self.coil.tagbyaddress:
                        self.coil.tagbyaddress[i].update(rr.bits[i-self.coil.minindex])
            if not self.input.minindex is None:                
                rr = self.client.read_discrete_inputs(self.input.minindex, self.input.maxindex-self.input.minindex+1,unit=self.unit)
                for i in range(self.input.minindex,self.input.maxindex+1):
                    if i in self.input.tagbyaddress:
                        self.input.tagbyaddress[i].update(rr.bits[i-self.input.minindex])
            if not self.holding.minindex is None:                    
                rr = self.client.read_holding_registers(self.holding.minindex, self.holding.maxindex-self.holding.minindex+1,unit=self.unit)
                for i in range(self.holding.minindex,self.holding.maxindex+1):
                    if i in self.holding.tagbyaddress:
                        self.holding.tagbyaddress[i].update(rr.registers[i-self.holding.minindex])
            if not self.register.minindex is None:                    
                rr = self.client.read_input_registers(self.register.minindex, self.register.maxindex-self.register.minindex+1,unit=self.unit)
                for i in range(self.register.minindex,self.register.maxindex+1):
                    if i in self.register.tagbyaddress:
                        self.register.tagbyaddress[i].update(rr.registers[i-self.register.minindex])
        except Exception as e:
            self.coil.plc.disconnect()
            printexception(e,"Error reading from PLC")

    def __Polling(plc):
        ''' Lectura de todas las áreas de escaneo.

        Establece la conexión con los controladores,
        si no se ha hecho antes, o se ha perdido.

        '''
        while True:
            if plc.connected:
                plc.read()
                time.sleep(plc.pollingtime)
            else:
                print("Connecting to MBPLC "+plc.address+":"+str(plc.port)+"("+str(plc.unit)+")")
                plc.connected=plc.client.connect()
Пример #3
0
def plugin_poll(handle):
    """ Poll readings from the modbus device and returns it in a JSON document as a Python dict.

    Available for poll mode only.

    Args:
        handle: handle returned by the plugin initialisation call
    Returns:
        returns a reading in a JSON document, as a Python dict, if it is available
        None - If no reading is available
    Raises:
    """

    try:
        global mbus_client
        if mbus_client is None:
            try:
                source_address = handle['address']['value']
                source_port = int(handle['port']['value'])
            except Exception as ex:
                e_msg = 'Failed to parse Modbus TCP address and / or port configuration.'
                _LOGGER.error('%s %s', e_msg, str(ex))
                raise ValueError(e_msg)
            try:
                mbus_client = ModbusTcpClient(host=source_address, port=source_port)
                mbus_client_connected = mbus_client.connect()
                if mbus_client_connected:
                    _LOGGER.info('Modbus TCP Client is connected. %s:%d', source_address, source_port)
                else:
                    raise RuntimeError("Modbus TCP Connection failed!")
            except:
                mbus_client = None
                _LOGGER.warn('Failed to connect! Modbus TCP host %s on port %d', source_address, source_port)
                return

        """ 
        read_coils(self, address, count=1, **kwargs)  
        read_discrete_inputs(self, address, count=1, **kwargs)
        read_holding_registers(self, address, count=1, **kwargs)
        read_input_registers(self, address, count=1, **kwargs)
        
            - address: The starting address to read from
            - count: The number of coils / discrete or registers to read
            - unit: The slave unit this request is targeting
            
            On TCP/IP, the MODBUS server is addressed using its IP address; therefore, the MODBUS Unit Identifier is useless. 

            Remark : The value 0 is also accepted to communicate directly to a MODBUS TCP device.
        """
        unit_id = UNIT
        modbus_map = json.loads(handle['map']['value'])

        readings = {}

        # Read coils
        coils_address_info = modbus_map['coils']
        if len(coils_address_info) > 0:
            for k, address in coils_address_info.items():
                coil_bit_values = mbus_client.read_coils(99 + int(address), 1, unit=unit_id)
                readings.update({k: coil_bit_values.bits[0]})

        # Discrete input
        discrete_input_info = modbus_map['inputs']
        if len(discrete_input_info) > 0:
            for k, address in discrete_input_info.items():
                read_discrete_inputs = mbus_client.read_discrete_inputs(99 + int(address), 1, unit=unit_id)
                readings.update({k:  read_discrete_inputs.bits[0]})

        # Holding registers
        holding_registers_info = modbus_map['registers']
        if len(holding_registers_info) > 0:
            for k, address in holding_registers_info.items():
                register_values = mbus_client.read_holding_registers(99 + int(address), 1, unit=unit_id)
                readings.update({k: register_values.registers[0]})

        # Read input registers
        input_registers_info = modbus_map['inputRegisters']
        if len(input_registers_info) > 0:
            for k, address in input_registers_info.items():
                read_input_reg = mbus_client.read_input_registers(99 + int(address), 1, unit=unit_id)
                readings.update({k: read_input_reg.registers[0] })

        wrapper = {
            'asset': handle['assetName']['value'],
            'timestamp': utils.local_timestamp(),
            'key': str(uuid.uuid4()),
            'readings': readings
        }

    except Exception as ex:
        _LOGGER.error('Failed to read data from modbus device. Got error %s', str(ex))
        raise ex
    else:
        return wrapper
Пример #4
0
data = {}
lastFilename = ''
while True:
    for ri in readList:
        result = '-'
        if ri['type'] == 0:
            result = client.read_coils(ri['address'],
                                       ri['count'],
                                       unit=args.unit)
        if ri['type'] == 1:
            result = client.read_discrete_inputs(ri['address'],
                                                 ri['count'],
                                                 unit=args.unit)
        if ri['type'] == 3:
            result = client.read_input_registers(ri['address'],
                                                 ri['count'],
                                                 unit=args.unit)
        if ri['type'] == 4:
            result = client.read_holding_registers(ri['address'],
                                                   ri['count'],
                                                   unit=args.unit)

        if ri['type'] < 2 and result != '-':
            i = 0
            for r in result.bits:
                data[str(ri['type']) + '_' + str(ri['address'] + i)] = str(
                    int(r))
                i += 1

        if ri['type'] > 2 and result != '-':
            i = 0