summaryrefslogtreecommitdiff
path: root/src/app/button-and-motion-logger/client.py
blob: 8d7317f01a277f6459fb35480c9b6d1226077a48 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#!/usr/bin/env python3
#
# Copyright 2020 Daniel Friesel
#
# SPDX-License-Identifier: BSD-2-Clause

import numpy as np
import paho.mqtt.client as mqtt
import re
import requests
import serial
import serial.threaded
import time

class SerialReader(serial.threaded.Protocol):
    """
    Character- to line-wise data buffer for serial interfaces.

    Reads in new data whenever it becomes available and exposes a line-based
    interface to applications.
    """
    def __init__(self, callback):
        """Create a new SerialReader object."""
        self.callback = callback
        self.recv_buf = ''

    def __call__(self):
        return self

    def data_received(self, data):
        """Append newly received serial data to the line buffer."""
        try:
            str_data = data.decode('UTF-8')
            self.recv_buf += str_data

            # We may get anything between \r\n, \n\r and simple \n newlines.
            # We assume that \n is always present and use str.strip to remove leading/trailing \r symbols
            # Note: Do not call str.strip on lines[-1]! Otherwise, lines may be mangled
            lines = self.recv_buf.split('\n')
            if len(lines) > 1:
                self.recv_buf = lines[-1]
                for line in lines[:-1]:
                    self.callback(str.strip(line))

        except UnicodeDecodeError:
            pass
            #sys.stderr.write('UART output contains garbage: {data}\n'.format(data = data))

class SerialMonitor:
    """SerialMonitor captures serial output for a specific amount of time."""

    def __init__(self, port: str, baud: int, callback):
        """
        Create a new SerialMonitor connected to port at the specified baud rate.

        Communication uses no parity, no flow control, and one stop bit.
        Data collection starts immediately.
        """
        self.ser = serial.serial_for_url(port, do_not_open=True)
        self.ser.baudrate = baud
        self.ser.parity = 'N'
        self.ser.rtscts = False
        self.ser.xonxoff = False

        try:
            self.ser.open()
        except serial.SerialException as e:
            sys.stderr.write('Could not open serial port {}: {}\n'.format(self.ser.name, e))
            sys.exit(1)

        self.reader = SerialReader(callback = callback)
        self.worker = serial.threaded.ReaderThread(self.ser, self.reader)
        self.worker.start()

    def close(self):
        """Close serial connection."""
        self.worker.stop()
        self.ser.close()

if __name__ == '__main__':

    mqtt = mqtt.Client()
    mqtt.connect('172.23.225.193');

    accel_factor = 2. / 32768
    gyro_factor = 250. / 32768
    magnet_factor = 150e-9

    accel_minmax = np.zeros((6))
    gyro_minmax = np.zeros((6))
    magnet_minmax = np.zeros((6))

    max_accel = 0
    max_magnet = 0
    vcc = 0
    intervals = [60, 300, 600, 3600, 7200]
    accel_by_5s = list()

    step = 0

    def parse_line(line):

        global max_accel
        global max_magnet
        global vcc

        match = re.match('button(.)', line)
        if match:
            mqtt.publish('sensor/button', int(match.group(1)))

        match = re.match('Min Accel: ([^ ]+) / ([^ ]+) / ([^ ]+)', line)
        if match:
            accel_minmax[0] = int(match.group(1)) * accel_factor
            accel_minmax[1] = int(match.group(2)) * accel_factor
            accel_minmax[2] = int(match.group(3)) * accel_factor

        match = re.match('Max Accel: ([^ ]+) / ([^ ]+) / ([^ ]+)', line)
        if match:
            accel_minmax[3] = int(match.group(1)) * accel_factor
            accel_minmax[4] = int(match.group(2)) * accel_factor
            accel_minmax[5] = int(match.group(3)) * accel_factor

        match = re.match('Min Gyro: ([^ ]+) / ([^ ]+) / ([^ ]+)', line)
        if match:
            gyro_minmax[0] = int(match.group(1)) * gyro_factor
            gyro_minmax[1] = int(match.group(2)) * gyro_factor
            gyro_minmax[2] = int(match.group(3)) * gyro_factor

        match = re.match('Max Gyro: ([^ ]+) / ([^ ]+) / ([^ ]+)', line)
        if match:
            gyro_minmax[3] = int(match.group(1)) * gyro_factor
            gyro_minmax[4] = int(match.group(2)) * gyro_factor
            gyro_minmax[5] = int(match.group(3)) * gyro_factor

        match = re.match('Min Magnet: ([^ ]+) / ([^ ]+) / ([^ ]+)', line)
        if match:
            magnet_minmax[0] = int(match.group(1)) * magnet_factor
            magnet_minmax[1] = int(match.group(2)) * magnet_factor
            magnet_minmax[2] = int(match.group(3)) * magnet_factor

        match = re.match('Max Magnet: ([^ ]+) / ([^ ]+) / ([^ ]+)', line)
        if match:
            magnet_minmax[3] = int(match.group(1)) * magnet_factor
            magnet_minmax[4] = int(match.group(2)) * magnet_factor
            magnet_minmax[5] = int(match.group(3)) * magnet_factor

        match = re.match('CPU VCC: ([^ ]+)', line)
        if match:
            vcc = int(match.group(1))

        match = re.match('MPU Temp: ([^ ]+)', line)
        if match:
            temp = float(match.group(1))
            max_accel = np.linalg.norm(accel_minmax[:3] - accel_minmax[3:])
            max_magnet = np.linalg.norm(magnet_minmax[3:])
            mqtt.publish('sensor/accel_g', max_accel)
            mqtt.publish('sensor/flux_t', max_magnet)
            #mqtt.publish('sensor/gyro_dps', np.linalg.norm(gyro_minmax[:3] - gyro_minmax[3:]))
            requests.post('http://192.168.0.200:8086/write?db=hosts', data='embedded,name=structure,area=hm17 mpu9250_degc={:f},mpu9250_mv={:d}'.format(temp, vcc))

    monitor = SerialMonitor('/dev/ttyUSB0', 57600, parse_line)

    try:
        while True:
            time.sleep(5)

            accel_by_5s.append(max_accel)
            step += 1

            if step == 4:
                for interval in intervals:
                    index_interval = int(interval / 5)
                    mqtt.publish('sensor/accel{}'.format(interval), max(accel_by_5s[ -index_interval : ]))
                accel_by_5s = accel_by_5s[ -intervals[-1] : ]
                step = 0

    except KeyboardInterrupt:
        monitor.close()
        mqtt.disconnect()