File: sensor_log_receiving_service.py

package info (click to toggle)
raritan-json-rpc-sdk 3.6.1%2Bds1-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 41,748 kB
  • sloc: cs: 162,629; perl: 85,818; python: 24,275; javascript: 5,937; makefile: 21
file content (143 lines) | stat: -rwxr-xr-x 5,143 bytes parent folder | download | duplicates (2)
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
#!/usr/bin/python3
# SPDX-License-Identifier: BSD-3-Clause
#
# Copyright 2019 Raritan Inc. All rights reserved.

from http.server import HTTPServer, BaseHTTPRequestHandler
import argparse, json, os
from netifaces import interfaces, ifaddresses, AF_INET
import os.path

def parse_cmdline():
    DESCR = """Starts a server which handles Xerus data push sensor log messages."""
    USAGE = "Usage: %prog [options]"
    script_name = os.path.splitext(os.path.basename(__file__))[0]
    default_path = "/tmp"
    default_output_file_path = "{0}/{1}.csv".format(default_path, script_name)

    parser = argparse.ArgumentParser(usage = USAGE, description = DESCR)

    h = "General options"
    grp = parser.add_argument_group(parser, h)
    grp.add_argument("-o", "--output", dest = "sensor_output_file_arg", default = default_output_file_path, help = "write received sensor logs to this file")
    grp.add_argument("-p", "--port", type=int, dest = "port_arg", default = 5080, help = "Port to connect to")

    return parser.parse_args()

class SensorPushHandler(BaseHTTPRequestHandler):
    SEPERATOR = ";"
    TIMESTAMP_ATTR = 'timestamp'
    LABEL_ATTR = 'label'
    ID_ATTR = 'id'
    STATE_ATTR = 'state'
    AVG_VALUE_ATTR = 'avgValue'

    def generate_csv_line(self, data_list):
        str_list = [ str(string) for string in data_list ]
        return self.SEPERATOR.join(str_list)

    def write_csv(self, fname, json_data):
        sensors = json_data['sensors']
        rows = json_data['rows']

        if len(sensors) > 0 and len(rows) > 0:
            titles = [ self.TIMESTAMP_ATTR ]
            for index, sensor in enumerate(sensors):
                label = sensor['device'][self.LABEL_ATTR].replace(" ", "-")
                sensor_id = sensor[self.ID_ATTR]
                sensor_title = "{0}_{1}_{2}".format(index, sensor_id, label)
                state_val_title = "{0}.{1}".format(sensor_title, self.STATE_ATTR)
                avg_val_title = "{0}.{1}".format(sensor_title, self.AVG_VALUE_ATTR)

                sensor_titles = [ state_val_title, avg_val_title ]
                titles.extend(sensor_titles)

            file_aready_exists = os.path.isfile(fname)
            with open(fname, mode="a+", encoding = "utf-8") as fd:
                titles_str = self.generate_csv_line(titles)

                if not file_aready_exists:
                    fd.write(titles_str)
                else:
                    # Move to the beginning of the file
                    fd.seek(0)
                    lines = fd.readlines()
                    last_line = lines[-1].split(self.SEPERATOR)
                    # Move to the end of the file
                    fd.seek(0, os.SEEK_END)

                    if len(titles) != len(last_line):
                        fd.write("\n\n" + titles_str)

                for index, row in enumerate(rows):
                    timestamp = row[self.TIMESTAMP_ATTR]

                    sensor_data = [ timestamp ]
                    for record in row['records']:
                        state_value = record[self.STATE_ATTR]
                        avg_value = record[self.AVG_VALUE_ATTR]

                        record_data = [ state_value, avg_value ]
                        sensor_data.extend(record_data)

                    sensor_data_str = self.generate_csv_line(sensor_data)
                    fd.write("\n" + sensor_data_str)
        else:
            print("Sensor data was empty.")

    def do_POST(self):
        content_length = int(self.headers['Content-Length'])
        body = self.rfile.read(content_length)
        self.send_response(200)
        self.end_headers()

        data_str = body.decode("utf-8")
        data = json.loads(data_str)
        self.write_csv(sensor_output_file, data)

class SensorLogListenerServer():
    httpd = None

    def __init__(self, port):
        # listen to everything not only localhost
        self.address = ("", port)
        self.start()

    def __del__(self):
        self.stop()

    def stop(self):
        if self.httpd != None:
            print("Shutting down server.")
            self.httpd.shutdown()
            self.httpd.server_close()

    def start(self):
        try:
            self.httpd = HTTPServer(self.address, SensorPushHandler)
            self.httpd.serve_forever()
        except KeyboardInterrupt:
            exit(1)

def ip4_addresses():
    ip_list = []
    for interface in interfaces():
        addrs = ifaddresses(interface)
        if AF_INET in addrs:
            for link in addrs[AF_INET]:
                if 'addr' in link:
                    ip_addr = link['addr']
                    ip_addr_str = "http://{0}:{1}".format(ip_addr, args.port_arg)
                    ip_list.append(ip_addr_str)
    return ip_list

args = parse_cmdline()

sensor_output_file = os.path.expanduser(args.sensor_output_file_arg)
ip_addresses_str = ", ".join(ip4_addresses())

print("Starting server and listen on the following addresses: {0}".format(ip_addresses_str))
print("Writing received data to '{0}'".format(sensor_output_file))

server = SensorLogListenerServer(args.port_arg)
server.start()