Merge pull request #6 from neurocis/main

Dockerize ready for InfluxDB

Related to issue #1
This commit is contained in:
sparky8512 2021-01-09 11:42:00 -08:00 committed by GitHub
commit 66a5c05d95
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 150 additions and 0 deletions

42
Dockerfile Normal file
View file

@ -0,0 +1,42 @@
FROM python:3.9
LABEL maintainer="neurocis <neurocis@neurocis.me>"
RUN true && \
# Install package prerequisites
apt-get update && \
apt-get install -qy cron && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
\
# Install GRPCurl
wget https://github.com/fullstorydev/grpcurl/releases/download/v1.8.0/grpcurl_1.8.0_linux_x86_64.tar.gz && \
tar -xvf grpcurl_1.8.0_linux_x86_64.tar.gz grpcurl && \
chown root:root grpcurl && \
chmod 755 grpcurl && \
mv grpcurl /usr/bin/. && \
rm grpcurl_1.8.0_linux_x86_64.tar.gz && \
\
# Install python prerequisites
pip3 install grpcio grpcio-tools paho-mqtt influxdb
ADD . /app
WORKDIR /app
# run crond as main process of container
CMD true && \
printenv >> /etc/environment && \
ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \
#ntpd -p pool.ntp.org && \
grpcurl -plaintext -protoset-out dish.protoset 192.168.100.1:9200 describe SpaceX.API.Device.Device && \
python3 -m grpc_tools.protoc --descriptor_set_in=dish.protoset --python_out=. --grpc_python_out=. spacex/api/device/device.proto && \
python3 -m grpc_tools.protoc --descriptor_set_in=dish.protoset --python_out=. --grpc_python_out=. spacex/api/common/status/status.proto && \
python3 -m grpc_tools.protoc --descriptor_set_in=dish.protoset --python_out=. --grpc_python_out=. spacex/api/device/command.proto && \
python3 -m grpc_tools.protoc --descriptor_set_in=dish.protoset --python_out=. --grpc_python_out=. spacex/api/device/common.proto && \
python3 -m grpc_tools.protoc --descriptor_set_in=dish.protoset --python_out=. --grpc_python_out=. spacex/api/device/dish.proto && \
python3 -m grpc_tools.protoc --descriptor_set_in=dish.protoset --python_out=. --grpc_python_out=. spacex/api/device/wifi.proto && \
python3 -m grpc_tools.protoc --descriptor_set_in=dish.protoset --python_out=. --grpc_python_out=. spacex/api/device/wifi_config.proto && \
echo "$CRON_ENTRY" | crontab - && cron -f
# docker run -e INFLUXDB_HOST=192.168.1.34 -e INFLUXDB_PORT=8086 -e INFLUXDB_DB=starlink
# -e "CRON_ENTRY=* * * * * /usr/local/bin/python3 /app/dishStatusInflux_cron.py > /proc/1/fd/1 2>/proc/1/fd/2"
# --net='br0' --ip='192.168.1.39' neurocis/starlink-grpc-tools

View file

@ -67,3 +67,18 @@ There are `reboot` and `dish_stow` requests in the Device protocol, too, so it s
The Starlink Android app actually uses port 9201 instead of 9200. Both appear to expose the same gRPC service, but the one on port 9201 uses an HTTP/1.1 wrapper, whereas the one on port 9200 uses HTTP/2.0, which is what most gRPC tools expect. The Starlink Android app actually uses port 9201 instead of 9200. Both appear to expose the same gRPC service, but the one on port 9201 uses an HTTP/1.1 wrapper, whereas the one on port 9200 uses HTTP/2.0, which is what most gRPC tools expect.
The Starlink router also exposes a gRPC service, on ports 9000 (HTTP/2.0) and 9001 (HTTP/1.1). The Starlink router also exposes a gRPC service, on ports 9000 (HTTP/2.0) and 9001 (HTTP/1.1).
## Docker for InfluxDB ( & MQTT under development )
`dishStatusInflux_cron.py` is a docker-cron friendly script which will post status to an InfluxDB as specified by evironment variables passed to the container. Initialization of the container can be performed with the following command:
```
docker run -e INFLUXDB_HOST={InfluxDB Hostname}
-e INFLUXDB_PORT={Port, 8086 usually}
-e INFLUXDB_USER={Optional, InfluxDB Username}
-e INFLUXDB_PWD={Optional, InfluxDB Password}
-e INFLUXDB_DB={Pre-created DB name, starlinkstats works well}
-e "CRON_ENTRY=* * * * * /usr/local/bin/python3 /app/dishStatusInflux_cron.py > /proc/1/fd/1 2>/proc/1/fd/2" neurocis/starlink-grpc-tools
```
Adjust the `CRON_ENTRY` to your desired polling schedule. I (neurocis) will push a Graphana dashboard in the near future, or please create and share your own.

93
dishStatusInflux_cron.py Normal file
View file

@ -0,0 +1,93 @@
#!/usr/bin/python3
######################################################################
#
# Write get_status info to an InfluxDB database.
#
# This script will poll current status and write it to
# the specified InfluxDB database.
#
######################################################################
import os
import grpc
import spacex.api.device.device_pb2
import spacex.api.device.device_pb2_grpc
from influxdb import InfluxDBClient
from influxdb import SeriesHelper
influxdb_host = os.environ.get("INFLUXDB_HOST")
influxdb_port = os.environ.get("INFLUXDB_PORT")
influxdb_user = os.environ.get("INFLUXDB_USER")
influxdb_pwd = os.environ.get("INFLUXDB_PWD")
influxdb_db = os.environ.get("INFLUXDB_DB")
class DeviceStatusSeries(SeriesHelper):
class Meta:
series_name = "spacex.starlink.user_terminal.status"
fields = [
"hardware_version",
"software_version",
"state",
"alert_motors_stuck",
"alert_thermal_throttle",
"alert_thermal_shutdown",
"alert_unexpected_location",
"snr",
"seconds_to_first_nonempty_slot",
"pop_ping_drop_rate",
"downlink_throughput_bps",
"uplink_throughput_bps",
"pop_ping_latency_ms",
"currently_obstructed",
"fraction_obstructed"]
tags = ["id"]
influx_client = InfluxDBClient(host=influxdb_host, port=influxdb_port, username=influxdb_user, password=influxdb_pwd, database=influxdb_db, ssl=False, retries=1, timeout=15)
dish_channel = None
last_id = None
last_failed = False
while True:
try:
if dish_channel is None:
dish_channel = grpc.insecure_channel("192.168.100.1:9200")
stub = spacex.api.device.device_pb2_grpc.DeviceStub(dish_channel)
response = stub.Handle(spacex.api.device.device_pb2.Request(get_status={}))
status = response.dish_get_status
DeviceStatusSeries(
id=status.device_info.id,
hardware_version=status.device_info.hardware_version,
software_version=status.device_info.software_version,
state=spacex.api.device.dish_pb2.DishState.Name(status.state),
alert_motors_stuck=status.alerts.motors_stuck,
alert_thermal_throttle=status.alerts.thermal_throttle,
alert_thermal_shutdown=status.alerts.thermal_shutdown,
alert_unexpected_location=status.alerts.unexpected_location,
snr=status.snr,
seconds_to_first_nonempty_slot=status.seconds_to_first_nonempty_slot,
pop_ping_drop_rate=status.pop_ping_drop_rate,
downlink_throughput_bps=status.downlink_throughput_bps,
uplink_throughput_bps=status.uplink_throughput_bps,
pop_ping_latency_ms=status.pop_ping_latency_ms,
currently_obstructed=status.obstruction_stats.currently_obstructed,
fraction_obstructed=status.obstruction_stats.fraction_obstructed)
last_id = status.device_info.id
last_failed = False
except grpc.RpcError:
if dish_channel is not None:
dish_channel.close()
dish_channel = None
if last_failed:
if last_id is not None:
DeviceStatusSeries(id=last_id, state="DISH_UNREACHABLE")
else:
# Retry once, because the connection may have been lost while
# we were sleeping
last_failed = True
continue
try:
DeviceStatusSeries.commit(influx_client)
except Exception as e:
print("Failed to write: " + str(e))
break