119 lines
4.0 KiB
Python
119 lines
4.0 KiB
Python
from os import getenv
|
|
import ipaddress
|
|
import wifi
|
|
import socketpool
|
|
import time
|
|
import random
|
|
|
|
random.seed(time.time())
|
|
random.random()
|
|
|
|
|
|
class NetworkHandler:
|
|
def __init__(self, sensor_class, listen_max_buffer, listen_timeout, listen_port, send_timeout, send_port):
|
|
self._sensor_class = sensor_class
|
|
self._wifi_connected = False
|
|
self._listen_socket = None
|
|
self._listen_max_buffer = listen_max_buffer
|
|
self._listen_timeout = listen_timeout
|
|
self._listen_port = listen_port
|
|
self._listen_buffer = bytearray(listen_max_buffer)
|
|
self._pool = None
|
|
self._host_addr = ''
|
|
self._listen_port = listen_port
|
|
self._send_addr = ''
|
|
self._send_port = send_port
|
|
self._send_socket = None
|
|
self._send_timeout = send_timeout
|
|
self._ssid = ''
|
|
|
|
def initialize(self):
|
|
self._connect_wifi()
|
|
while not self._wifi_connected:
|
|
time.sleep(15)
|
|
self._connect_wifi()
|
|
print('WiFi connected -', self._ssid)
|
|
self._pool = socketpool.SocketPool(wifi.radio)
|
|
self._host_addr = str(wifi.radio.ipv4_address)
|
|
print(self._host_addr)
|
|
self._setup_listen_socket()
|
|
print(f'Send addr: "{self._send_addr}"')
|
|
while len(self._send_addr) == 0:
|
|
print('Trying to connect to CarOS host', time.time())
|
|
if self._receive_udp():
|
|
break
|
|
time.sleep(random.randint(1, 10) / 10)
|
|
|
|
def update(self):
|
|
if self._receive_udp():
|
|
return
|
|
|
|
def send(self, message):
|
|
if self._send_addr is None or self._send_socket is None:
|
|
print(self._send_addr, self._send_socket)
|
|
return
|
|
buffer = bytearray(message)
|
|
|
|
ck_a, ck_b = self._calculate_checksum(buffer)
|
|
buffer[-2] = ck_a
|
|
buffer[-1] = ck_b
|
|
try:
|
|
self._send_socket.sendto(buffer, (self._send_addr, self._send_port))
|
|
except Exception as e:
|
|
print("Error while sending data to: '", self._send_addr, "'", self._send_port)
|
|
print(e)
|
|
|
|
def _send_peer_request(self):
|
|
print("Send peer request")
|
|
message = bytearray(b'\xd4\x53\x6E\x77\x00')
|
|
message[-1] = self._sensor_class
|
|
message += '\x00' + '\x00'
|
|
self.send(message)
|
|
|
|
def _calculate_checksum(self, packet):
|
|
ck_a = 0
|
|
ck_b = 0
|
|
for i in range(2, len(packet) - 2):
|
|
ck_a += packet[i]
|
|
ck_b += ck_a
|
|
return [ck_a % 0x100, ck_b % 0x100]
|
|
|
|
def _connect_wifi(self):
|
|
self._ssid = getenv("CIRCUITPY_WIFI_SSID")
|
|
print(f'Trying to connect to "{self._ssid}"')
|
|
password = getenv("CIRCUITPY_WIFI_PASSWORD")
|
|
try:
|
|
wifi.radio.connect(self._ssid, password)
|
|
self._wifi_connected = True
|
|
except Exception as e:
|
|
print("Could not find WiFi info. Check your settings.toml file!")
|
|
self._wifi_connected = False
|
|
|
|
def _setup_listen_socket(self):
|
|
self._listen_socket = self._pool.socket(self._pool.AF_INET, self._pool.SOCK_DGRAM)
|
|
self._listen_socket.settimeout(self._listen_timeout)
|
|
self._listen_socket.bind((self._host_addr, self._listen_port))
|
|
|
|
def _setup_send_socket(self):
|
|
self._send_socket = self._pool.socket(self._pool.AF_INET, self._pool.SOCK_DGRAM)
|
|
self._send_socket.settimeout(self._send_timeout)
|
|
|
|
def _receive_udp(self):
|
|
send_addr = None
|
|
try:
|
|
size, addr = self._listen_socket.recvfrom_into(self._listen_buffer)
|
|
data = self._listen_buffer[:size].decode('utf-8')
|
|
send_addr, time_str = data.split('|')
|
|
print('Data received:', data)
|
|
except OSError:
|
|
return False
|
|
if send_addr is None:
|
|
return False
|
|
if send_addr != self._send_addr:
|
|
self._send_addr = send_addr
|
|
if self._send_socket:
|
|
self._send_socket.close()
|
|
self._setup_send_socket()
|
|
self._send_peer_request()
|
|
return True
|