Description
Hi, I'm looking to use the Feather M4 Express and Ethernet FeatherWing as a way to collect I2C sensor data with Prometheus and threw together a very small HTTP server for that purpose. It works pretty well with light traffic, but if the socket.accept
waits too long for an incoming request, the board seems to fall off the network and my code soft-reboots without raising an error:
Headers: {'http': 'HTTP/1.1', 'method': 'GET', 'path': '/favicon.ico'}
Connection: ('10.2.1.193', 8080)
Code done running. Waiting for reload.
soft reboot
Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
code.py output:
['0x40', '0x77']
Online: True
Network: ('0.0.0.0', '0.0.0.0', '0.0.0.0', '0.0.0.0')
When no requests are incoming, I would like the socket.accept
to break after a few seconds to let the network driver run and take another sample from the sensors.
The docs and source seem to support socket.settimeout
but it appears to invoke a method (syscall?) on the NIC, which throws:
Online: True
Network: ('0.0.0.0', '0.0.0.0', '0.0.0.0', '0.0.0.0')
Online: True
Network: ('10.2.2.254', '255.255.0.0', '10.2.1.1', '0.0.0.0')
Binding: 10.2.2.254:8080
Unable to set socket timeout: [Errno 22] Invalid argument
Is there a way to make the socket timeout, have a timer interrupt it, or work around this somehow?
Running:
Adafruit CircuitPython 4.1.0 on 2019-08-02; Adafruit Feather M4 Express with samd51j19
My socket setup code is:
def start_http_server(port, address='0.0.0.0'):
bind_address = (address, port)
http_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
http_socket.bind(bind_address)
http_socket.listen(1)
try:
http_socket.settimeout(5.0)
except OSError as err:
print('Unable to set socket timeout:', err)
return Server(http_socket)
class Server():
http_socket = False
def __init__(self, http_socket):
self.http_socket = http_socket
def accept(self, router):
conn, addr = self.http_socket.accept()
print('Connection: {}'.format(addr))
req = conn.recv(1024).decode(http_encoding)
req_headers = self.parse_headers(req)
print('Headers: {}'.format(req_headers))
handler = router.select(req_headers['method'], req_headers['path'])
resp = handler(req_headers, '')
def main():
ready = False
bound = False
registry = CollectorRegistry(namespace='prom_express')
metric_gas = Gauge('gas',
'gas from the bme680 sensor', registry=registry)
metric_humidity = Gauge('humidity',
'humidity from both sensors', ['sensor'], registry=registry)
metric_pressure = Gauge('pressure',
'pressure from the bme680 sensor', registry=registry)
metric_temperature = Gauge('temperature',
'temperature from both sensors', ['sensor'], registry=registry)
def prom_handler(headers, body):
return {
'status': '200 OK',
'content': '\r\n'.join(registry.print()),
}
router = Router([
('GET', '/metrics', prom_handler),
])
server = False
rgb[0] = RED # starting
while not ready:
ready = check_network(eth)
led.value = ready
rgb[0] = BLUE # connected
while not bound:
server, bound = bind_server(eth)
rgb[0] = GREEN # ready
while True:
metric_gas.set(sensor_bme680.gas)
metric_humidity.labels('bme680').set(sensor_bme680.humidity)
metric_humidity.labels('si7021').set(sensor_si7021.relative_humidity)
metric_pressure.set(sensor_bme680.pressure)
metric_temperature.labels('bme680').set(sensor_bme680.temperature)
metric_temperature.labels('si7021').set(sensor_si7021.temperature)
try:
server.accept(router)
except OSError as err:
print('Error accepting request: {}'.format(err))
server, bound = bind_server(eth)
except Exception as err:
print('Unknown error: {}'.format(err))
With a more complete example here: https://github.com/ssube/prometheus_express/blob/master/examples/feather-m4-i2c.py