Make Your Own Sensor Driver

Using the Data Logger Application provided by Observator you can easily integrate your own sensor (driver). Please study the manual on how to use the OMC-048 Data Logger Application before you start integrating your own sensor driver.

Creating a .py driver file

Create a new .py file and place this in the scriptmodules folder of your OMC-048 data logger. In this example we create the file ‘simple_driver.py’ but you are free to choose any name you like, as long as there are no duplicate names.

Now paste the following code in your driver file:

simple_driver.py
 1from sensor_drv import SensorDrv
 2
 3class simple_driver(SensorDrv):
 4
 5    def __init__(self, serial, conf):
 6        SensorDrv.__init__(self)
 7
 8    async def read_values(self):
 9        self.data = [0]
10        return True
11
12    async def detect_parameters(self, tag_number = ''):
13        self.parameters = [('parameter', '', 'TAG{}'.format(tag_number))]
14        return True
15
16    async def flush(self):
17        pass

Important

The class name (line 3) must be identical to the .py file name!

Add your own driver code

In this example we are simulating a sensor which transmits data over RS422 on serial port 1 on 1 Hz interval.

  • serial port 1

  • 9600 baud, 8N1

The string transmitted by the sensor is:

Temp=20.34,Hum=56.4,Status=OK\r\n

In our example we want to capture three fields of data: Temperature, Humidity and Status

We start by adding the parameters to the driver: name, unit and unique tag. We must also provide 3 value’s to ‘self.data’ in the ‘read_values’ function, corresponding to the given parameters. For now we just enter the decimal values 1, 2 and 3.

simple_driver.py
 1from sensor_drv import SensorDrv
 2
 3class simple_driver(SensorDrv):
 4
 5    def __init__(self, serial, conf):
 6        SensorDrv.__init__(self)
 7
 8    async def read_values(self):
 9        self.data = [1,2,3]
10        return True
11
12    async def detect_parameters(self, tag_number = ''):
13        self.parameters = [ ('Temperature', '', 'TMP{}'.format(tag_number)),
14                            ('Humidity', '', 'HUM{}'.format(tag_number)),
15                            ('Status', '', 'STS{}'.format(tag_number)) ]
16        return True
17
18    async def flush(self):
19        pass

Test your driver

The base for our sensor driver is now provided, we can already test it by adding our sensor driver to the config.txt The entire config is displayed below, note the ‘simple_driver’ for our example.

# ----System---- #
Omc048:
  system_id: PROTO_1
  application: PROTO_1
  file_log_level: info
  repl_log_level: info
  utc_time_offset_hours: +0
  utc_time_offset_minutes: +0
  sensor_data_print: True
  usb_mode: debug
  self_test: False

simple_driver:
- id: simple_1
  sample_interval: "* * * * *"
  port: serial1
  mode: RS422
  baudrate: 9600

# ----Data-log-settings---- #
Data_file:
- id: data
  create_interval: "0 0,5,10,15,20,25,30,35,40,45,50,55 * * *"

Using the REPL to start our application shows our driver is working:

2022-06-10 10:00:02 [APPLICATION] INFO config.txt detected
2022-06-10 10:00:02 [APPHELPER] INFO DEBUG mode is active
2022-06-10 10:00:02 [APPLICATION] INFO UTC time device offset: 0(hrs):0(min)
2022-06-10 10:00:02 [DRIVER_MANAGER] INFO Acquiring parameters simple_driver sensor: simple_1
2022-06-10 10:00:02 [DRIVER_MANAGER] INFO simple_driver sensor detected: simple_1
2022-06-10 10:00:02 [LOGGER_MANAGER] INFO Log parameters appended: simple_1
2022-06-10 10:00:02 [APPLICATION] INFO Application started: PROTO_1
2022-06-10 10:00:02 [APPLICATION] INFO File Syslog level: info
2022-06-10 10:00:02 [APPLICATION] INFO Repl Syslog level: info
2022-06-10 10:00:02 [DATALOG045] INFO Started logging in 'data/OMC-045_PROTO_1_048000201_220610_100002.txt'
2022-06-10 10:00:02 [SCHEDULER] INFO Enabled sleeping in between tasks
2022-06-10 10:00:03 [DRIVER_MANAGER] INFO Sensor [simple_1] power on
2022-06-10 10:00:03 [DRIVER_MANAGER] INFO Sensor [simple_1] data successfully obtained
2022-06-10 10:00:03 [DRIVER_MANAGER] INFO Sensor [simple_1] power off
  Sensor data: ('Temperature', '', 'TMP_simple_1') 1
  Sensor data: ('Humidity', '', 'HUM_simple_1') 2
  Sensor data: ('Status', '', 'STS_simple_1') 3
2022-06-10 10:00:03 [SCHEDULER] INFO Sleep for 0.749 seconds
2022-06-10 10:00:04 [DRIVER_MANAGER] INFO Sensor [simple_1] power on
2022-06-10 10:00:04 [DRIVER_MANAGER] INFO Sensor [simple_1] data successfully obtained
2022-06-10 10:00:04 [DRIVER_MANAGER] INFO Sensor [simple_1] power off
  Sensor data: ('Temperature', '', 'TMP_simple_1') 1
  Sensor data: ('Humidity', '', 'HUM_simple_1') 2
  Sensor data: ('Status', '', 'STS_simple_1') 3

Note

The base of our sensor is operational now, from this point we can start adding the actual sensor driver by reading the data string over the given serial port.

Simulating the data

We now need to simulate the data, this can be done using a generic serial talker or use another OMC-048 using the script below:

import omc048, obs

print("simple_driver sensor simulator")
s2 = omc048.serial(2)
s2.init(9600, s2.RS422, txbuf=1024)

sensor_data = "Temp=20.34,Hum=56.4,Status=OK\r\n"

while True:
    s2.write(sensor_data)
    print(sensor_data)
    obs.delay(1000)

Connect the simulated sensor output to the OMC-048 data logger and edit the simple_driver file to the example below:

simple_driver.py
 1from sensor_drv import SensorDrv
 2from read_line import Read_line
 3
 4    class simple_driver(SensorDrv):
 5
 6        def __init__(self, serial, conf):
 7            SensorDrv.__init__(self)
 8            self.__serial_data = Read_line(serial)
 9
10        async def read_values(self):
11            while True:
12                received = await self.__serial_data.update()
13                if received:
14                    print('received data:', received)
15                    data = received[0].decode()
16                    data_replace = data.replace('\r\n','')
17                    data_replace = data_replace.replace('=',',')
18                    data_split = data_replace.split(',')
19                    print('split data:', data_split)
20                    break
21            self.data = [data_split[1],data_split[3],data_split[5]]
22            return True
23
24        async def detect_parameters(self, tag_number = ''):
25            self.parameters = [ ('Temperature', '', 'TMP{}'.format(tag_number)),
26                                ('Humidity', '', 'HUM{}'.format(tag_number)),
27                                ('Status', '', 'STS{}'.format(tag_number)) ]
28            return True
29
30        async def flush(self):
31            pass

Note

We have used the read_line module to collect the data. Prints were added on the original input data as wel as the split data to show the results

Running the application presents us the following:

received data: [b'Temp=20.34,Hum=56.4,Status=OK\r\n']
split data: ['Temp', '20.34', 'Hum', '56.4', 'Status', 'OK']
2022-06-10 10:52:14 [DRIVER_MANAGER] INFO Sensor [simple_1] data successfully obtained
  Sensor data: ('Temperature', '', 'TMP_simple_1') 20.34
  Sensor data: ('Humidity', '', 'HUM_simple_1') 56.4
  Sensor data: ('Status', '', 'STS_simple_1') OK

This concludes our simple driver example. Your own sensor driver now workes as any other! The data is automatically added to the logs!

Important

  • The ‘detect_parameters’ is executed on startup and should actually check for a present sensor, this prevents the sensor from being scheduled if not attatched.

  • The ‘read_values’ is executed every given cron interval and should only return ‘True’ in case the sensor reading was succesfully obtained and ‘self.data’ filled with data.

  • You can add sensor specific settings to the config.txt file by using the config module!

  • There are many sensor drivers you can use as an example, you can find them in the ‘script/modules’ folder

Tip

Can’t get it figured out? Feel free to contact us!