Analysis of UDP Data Transferred by python Meteorological Equipment-Notes

Posted by BSlepkov on Wed, 31 Jul 2019 08:06:39 +0200

Articles Catalogue

Background

Recently, in a company's equipment, the built-in DTU sends 16-digit data messages to the server through UDP. Because of the first contact with this kind of data analysis method, we summarize and reflect here to avoid detours.

II. Summary of Contents

2.1 Creation of UDP Communication Server

step

  1. Create UDP socket communication mode.
  2. Bind specific ports.
  3. Setting up port multiplexing wait (this step can be omitted)
  4. Get data.
  5. Send data to client.
  6. Parse and store data.
  7. Close the socket link for UDP.

Following are the explanations and summaries, which are adopted. MVP Complete all the above steps in a way that does not extend too much:

1. Create UDP socket communication mode.

import socket
Server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

Before any type of communication starts, a network application must create a socket.
Sockets were originally created for applications on the same host, enabling one program (aka a process) running on the host to communicate with another. This is called Inter Process Communication (IPC).
There are two types of nested words:

  • File-based: AF_UNIX
  • Network-oriented: AF_INET (IPv4-oriented), AF_INET6 (IPv6-oriented)

DUP uses connectionless sockets

  • Features: unreliable (intranet or more reliable), low overhead. In order to create UDP sockets, SOCK_DGRAM must be used as the socket type. The SOCK_DGRAM name of a UDP socket comes from the word "datagram".

2. Binding specific ports

Server.bind("", 8600)

bind means that the created Server will be bound to a specific port. Note:
As a UDP server, the IP address in front can be omitted, and the valid port number in the back ranges from 0 to 65535 (the port number less than 1024 is reserved for the system).

Setting up port reuse waiting (this step can be omitted)**

Server.setsockopt(socket.IPPROTO_IP, socket.SO_REUSEADDR, 1)

If the port has been used and the port link has been closed with Socket.close(), but the port has not yet been released, the above function can be used to wait for the port to be re-invoked.

4. Data acquisition

Msg, ClientAddr = Server.recvfrom(1024)

In UDP, recvform returns the ** byte stream (decimal, ASCII code, hexadecimal, etc.) sent by the client and the IP address of the client. 1024 indicates the size of the cached data.

5. Send data to client

Server.sendto(Data)

Usually UDP server sends heartbeat packet confirmation to client after receiving data, and data can be sent through this function.

6. Parsing data

Data = binascii.b2a_hex(Msg)

This function parses the transmitted byte stream message data into hexadecimal data. Opinions on relevant usage Byte stream conversion to ASCII code

7. Close the socket link for UDP

Server.close()

There's nothing to say, just have it, or you won't be able to continue using this port next time.

2.2 16-digit data parsing

1. Packet Time Resolution

Time = datetime.datetime.strptime(Data[26:38], "%y%m%d%H%M%S")  # Resolution time

Because time is decimal data, there is no need to do hexadecimal conversion here, directly through datetime strptime method for data conversion.

2. Converting hexadecimal system to 10-decimal system and then to ASCII code

chr(int(Data[224 + (i - 2):224 + i],16))

int(num, 16) converts 16 to 10
Chr (decimal) parses the corresponding ASCII code

2.3 File Creation and Data Storage Analysis

I have to say that I encountered a lot of pits when I stored data files.
Pit 1: How to automatically create folder structure of year - > month - > day?

When creating folders, I have thought of using makedirs() function chain to create folders, but I always reported errors when judging whether the folder exists. I have always thought that it was caused by improper use of makedirs(), and I have thought of using chdir function and mkdir() function to create folders step by step. The final effect is as follows. Nor is it particularly good. Later, after careful examination of the data for a long time, it was found that:

if not os.path.exists(NewPath):
    os.makedirs(NewPath)

When judging whether a folder exists in the default IDLE, there has always been a problem that will cause an error. After a long time, it changed to:

if not os.path.isdir(FileDir):
     os.makedirs(FileDir)

No mistake. Take notes here to remind yourself.

These are all the mistakes I have summarized. I hope you can avoid these pits when you read this post. Below is my complete UDP message receiving and parsing code:

#!/usr/local/bin/python3
# coding:utf-8

import socket
import binascii
import datetime
import os
import csv

'''
//Author: Zflyee
Mailto: zflyee@126.com
'''

Server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # Create UDP to transfer data
# Server.setsockopt(socket.IPPROTO_IP, socket.SO_REUSEADDR, 1)    # Fast Implementation of Port Multiplexing

Server.bind(("", 8600))
print(u"Binded native port:8600,Data is being monitored...")


def DataParsing(Data):
    Time = datetime.datetime.strptime(Data[26:38], "%y%m%d%H%M%S")  # Resolution time

    Voltage = int(Data[44:46], 16) / 10.0  # Voltage data

    Temp = int(Data[60:64], 16) / 10.0  # Real-time temperature data

    Temp_1h_max = int(Data[70:74], 16) / 10.0  # Hourly maximum temperature

    Temp_1h_min = int(Data[80:84], 16) / 10.0  # Minimum Temperature Hour

    Hum = int(Data[90:94], 16) / 10.0  # Humidity data

    Hum_1h_max = int(Data[100:104], 16) / 10.0  # Maximum Humidity Hour

    Hum_1h_min = int(Data[110:114], 16) / 10.0  # Minimum Humidity Hour

    Pa = int(Data[120:124], 16) / 10.0  # Barometric data

    Pa_1h_max = int(Data[130:134], 16) / 10.0  # Maximum air pressure hourly

    Pa_1h_min = int(Data[150:154], 16) / 10.0  # Minimum air pressure hour

    WindSpd = int(Data[140:144], 16) / 10.0  # Instantaneous wind speed

    WindSpd_10min_avg = int(Data[160:164], 16) / 10.0  # Average 10-minute wind speed

    WindSpd_max = int(Data[170:174], 16) / 10.0  # Maximum current wind speed

    WindSpd_min = int(Data[180:184], 16) / 10.0  # Current minimum wind speed

    WindDir = int(Data[190:194], 16) / 10.0  # Current Wind Direction Instantaneous Value

    WindDir_10min_avg = int(Data[200:204], 16) / 10.0  # 10-minute mean wind direction

    Rain_1day = int(Data[210:214], 16) / 10.0  # Daily rainfall

    # Estimating the Length of Latitude Data
    Lati_len = int(Data[220:224], 16)  # Conversion to 10-digit
    Lati = ""
    for i in range(2, Lati_len * 2, 2):
        Lati += (chr(int(Data[224 + (i - 2):224 + i], 16)))

    # Estimating Dimension Length and Data
    Long_len = int(Data[250:252], 16)
    Long = ""
    for i in range(2, Long_len * 2, 2):
        Long += (chr(int(Data[254 + (i - 2):254 + i], 16)))

    # Assemble data
    DataList = [Time, WindSpd, WindSpd_10min_avg, WindSpd_max, WindSpd_min, WindDir, WindDir_10min_avg,
                Temp, Temp_1h_max, Temp_1h_min, Hum, Hum_1h_max, Hum_1h_min, Pa, Pa_1h_max, Pa_1h_min, Rain_1day,
                Voltage]

    # Create a file path
    Path = "E:\\Fuoton\\data\\SY_FWS600\\"
    Text = os.path.join(Path, Time.strftime("%Y"), Time.strftime("%m")) + "\\" + Time.strftime("%d") + ".csv"
    FileDir = os.path.split(Text)[0]
    if not os.path.isdir(FileDir):
        os.makedirs(FileDir)
    # Write data
    with open(Text, "a+", newline="") as f:
        Writer = csv.writer(f)
        Writer.writerow(DataList)
    # Storage tips
    print(u"{}Time data has been successfully stored.".format(Time))

while True:
    try:
        Msg, ClientAddr = Server.recvfrom(1024)
        Data = binascii.b2a_hex(Msg)  # Converting data into hexadecimal data
        Data = str(Data, encoding="utf-8")
        print(u"from{0}Of{1}The port gets the following data:\n{2}".format(ClientAddr[0], ClientAddr[1], Data))
        if Data[0:2] == "7b":
            Content = "7B810010" + Data[8:30] + "7B"
            Response = binascii.a2b_hex(Content)
            Server.sendto(Response, ClientAddr)  # Reply to client data
            print(u"Replied Client")
        elif Data[0:2] == '01':
            DataParsing(Data)
        else:
            print(u"%%%%%%%%%%%%%%%Data Error Reporting and Retrieval%%%%%%%%%%%%%%%")
            continue
    except:
        print(u"%%%%%%%%%%%%%%%Data Error Reporting and Retrieval%%%%%%%%%%%%%%%")
        continue


Server.close()

Topics: Big Data socket ascii network less