akYtec PR200 Prototype V1

Short overview to get started with the akYtec PR200 Prototype

Prototype features

The akYtec PR200 prototype comes with the following functionality:

  • 2 digital outputs (DO1 and DO2 on the PR200)

  • 2 analog inputs (AI1 and AI2 on the PR200) (currently 0-10V)

  • Digital outputs can be monitored and controlled (switched) via the OneIoT Cloud and Dashboard.

  • Analog inputs can be monitored via the OneIoT Cloud and Dashboard.

It is easy to extend this functionality via the Instrument Driver.

Quick Start Guide

  • Connect the OneIoT Gateway via USB Micro B connector (5 Volts)

Make sure you only connect 5 Volts DC to the Gateway.

  • Connect the RJ45 Jack of the OneIoT Gateway to a LAN which provides access to internet

In some LANs outgoing ports might be blocked. In case the device will not connect to the cloud, you need to open ports 8883 for MQTTs-Connection and 9090 for Over-The-Air Updates.

  • Connect the OneIoT Gateway to the device via Modbus. A+ (green wire) has to be connected to the D+ port of the PR200 and B- (blue wire) has to be connected to the D- port of the PR200. Use the first (left most) RS485 interface of the PR200.

For the prototype, make sure the RS485 connector of the OneIoT Gateway is connected to the OneIoT Gateway (all for wires should be connected).

  • Connect some analog inputs or digital outputs.

  • Connect 24V DC power supply to the PR200 power input. Also, consult the PR200 manual for more details or in case of any doubts.

Make sure you never connect >24V DC to the PR200 power input.

In case the gateway is not shown in the list, you need to link it to your account first. If it is shown in the list but does not appear to be online (grey circle), check the power connection and make sure that the gateway can connect to the internet via the LAN.

  • If the OneIoT Gateway is online, you can create or modify your own dashboard.

The PR200 prototype showcase

There is a small ALP program running on the PR200. It has the following responsibilities:

  • The PR200 is in Modbus Slave-Mode and available via address 16.

  • The network variables Eingang1 and Eingang2 are mapped to register 512 and 513, respectively.

  • Eingang1 and Eingang2 are connected to the digital output Q1 and Q2, respectively.

  • Analog inputs are made available by default via Modbus as described in the PR200 manual.

  • Analog input 1 is shown in the PR200 display.

The demo program is included on the USB stick.

In the OneIoT Cloud there is a so called Device Template for the PR200. This template describes the device in the cloud. The mapping is based on the OneIoT Digital Twin concept. Variables are mapped to so called Items:

PR200

OneIoT Item

AI1

Analog Input 1 (Item 1)

AI2

Analog Input 2 (Item 2)

Q1

Relais 1 (Item 3)

Q2

Relais 2 (Item 4)

The Device Template can then be used to define Dashboards.

The Device Template can be changed and extended at anytime. The Instrument Driver, which can also be changed at runtime (e.g., by the user or by OneIoT) is responsible to fetch the data from the PR200 and forward it to the cloud via the defined items.

There is already a OneIoT Dashboard for this showcase.

Custom driver to support every possible use case

A Instrument Driver is responsible for the communication between OneIoT Gateway and PR200.

The Instrument Driver can also be adapted at runtime!

In the future, there will be an easier to use Domain Specific Language for Modbus-based drivers.

The current prototype instrument driver is given below. It just fetches some values via Modbus every 30 seconds and sends them to the cloud. Furthermore, incoming commands from the OneIoT Cloud, that is, switching one of the relays are mapped to the corresponding Modbus commands and send to the PR200.

This code can easily extended to read all registers from the PR200 or to write and read all network variables. Furthermore, I can be adapted to specific use cases. For example, sensor readings can be evaluated and aggregated and complex logic can be implemented here.

OneIoT provides support in writing instrument drivers.

import struct
import uasyncio as asyncio
import logging
from serial_communication import Serial
from queue import MESSAGE_BUS, Event, EVENT_TO_CLOUD_FOR_MQTT, EVENT_ERROR
import message_util
from libs.modbus_facade import ModbusFacade

class CustomHandler:

    def __init__(self, serial:Serial):
        # Every 30sec
        self.fire_every = 30
        self.modbus = ModbusFacade(serial)

    async def loop(self):
        # Read every x seconds
        while True:
            await asyncio.sleep_ms(self.fire_every*1000)
            # Address 0x10, 0x0B00-0x0B01 is AI1
            answer_double_list = await self.modbus.read_holding_registers(0x10, 0x0B00, 0x02, double_valued=True)
            # Item 1 mapped to AI 1
            await self.send_double(1, answer_double_list[0])
            # Address 0x10, 0x0B02-0x0B03 is AI1
            answer_double_list = await self.modbus.read_holding_registers(0x10, 0x0B02, 0x02, double_valued=True)
            # Item 2 mapped to AI 2
            await self.send_double(2, answer_double_list[0])
            # Address 0x10, 0x2000 is network variable 1
            answer_bool_list = await self.modbus.read_coils(0x10, 0x2000, 0x01)
            print(answer_bool_list)
            # Item 3 mapped to network variable 1
            await self.send_bool(3, answer_bool_list[0])
             # Address 0x10, 0x2001 is network variable 2
            answer_bool_list = await self.modbus.read_coils(0x10, 0x2010, 0x01)
            print(answer_bool_list)
            # Item 3 mapped to network variable 1
            await self.send_bool(4, answer_bool_list[0])
            
    async def handle_incoming(self, message):
        if message_util.get_state_content_for_payload(message) is not None:
            item_number, state_str = message_util.get_state_content_for_payload(message)
            item_number = int(item_number)
            # state is expected to be boolean and we'll send it via single_coil function code
            if state_str == "0":
                state = 0x0000
            elif state_str == "1":
                state = 0xFF00
            # Only network variables 1 and 2 bound to item 3 and 4 will be handled
            if item_number == 3:
                register = 0x2000
            if item_number == 4:
                register = 0x2010
            # write single coil
            if not await self.modbus.write_single_coil(0x10, register, state):
                logging.log("Writing register failed.")        
        else:
            logging.log(str("Cannot handle message %s." % str(message)))        
        
            
    async def send_bool(self, item, value):
        if value:
            await self.send_message(item, "1", "BOOLEAN")
        else:
            await self.send_message(item, "0", "BOOLEAN")
        
    async def send_double(self, item, value):
        value = str(value)
        await self.send_message(item, value, "DOUBLE")
        

    async def send_message(self, item, value_string, type="DOUBLE"):
        message = None
        if value_string:
            message =  "S:" + str(item) + ":20:" + type + ":" + value_string
        else:
            message =  "S:" + str(item) + ":50"
            logging.log("No answer received for command...")

        await self.finalize_serial_to_cloud(message)
        # TODO log to cloud

    '''
    This finalizes a serial message given the OneIoT protocol. Timestamp is added and message is checked.
    Then it is sent to the cloud.
    '''
    async def finalize_serial_to_cloud(self, message):
        message = message_util.add_timestamp(message)
        correct = message_util.check_serial_message(message)
        if not correct:
            await MESSAGE_BUS.send(Event(EVENT_ERROR, "Incorrect handled serial: " + message))
        else:
            # just forward to devicecloud via MQTT
            await MESSAGE_BUS.send(Event(EVENT_TO_CLOUD_FOR_MQTT, [message]))

Mobus Settings

PR200 modbus settings:

Property

Value

Address

16 (decimal) = 0x10 (hex)

Baud

9600

Stop Bits

1

Parity

None

Data Bits

8

Troubleshooting

1.) Device does not show up online in the Device Cloud, there is only a grey circle!

Check your connection, make sure all necessary outgoing ports are open (9090, 8883, 80, 443). Make sure, the device has access to the internet. In case you are using a mobile connection, make sure you have sufficient radio reception. You can also move the gateway to another location to check reception issues.

2.) Device does not show up at all!

You need to onboard the device first.

3.) Device seems to be online (green circle) but I can see no Dashboard!

Option 1: Go to another device page, for example the Debugging Page and then back to the Dashboard. If the Dashboard does not show up then, you have not created one yet (see Option 2). Option 2: Create a new Dashboard.

4.) Device seems to be online (green circle) but I don't receive any data!

Option 1: Refresh (Press F5 on the keyboard) the Dashboard. Option 2: If you can not see any data, even though you know some sensor readings should have been received, make sure your mapping (Device Template) to the items is correct (i.e., the Dashboard displays the right data in the widgets). Option 3: If mapping is correct and data should be received but is not shown in the cloud, make sure your physical connection is correct. Test the OneIoT Gateway or your device also with another device or Modbus master, respectively.

Last updated