Compare commits
10 Commits
6c0054e72d
...
master
Author | SHA1 | Date | |
---|---|---|---|
83e838c9b7 | |||
741baa3c7a | |||
0d7b2a4935 | |||
cd8204e020 | |||
be6fb4bc3c | |||
ae30c39954 | |||
4a8d130c72 | |||
ad34a4b2d2 | |||
127c6ef91c | |||
84a643e69c |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -101,3 +101,5 @@ ENV/
|
|||||||
# Editor
|
# Editor
|
||||||
*.swp
|
*.swp
|
||||||
*.swo
|
*.swo
|
||||||
|
|
||||||
|
out.txt
|
||||||
|
@@ -1,6 +1,4 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
class ApiConfig(AppConfig):
|
class ApiConfig(AppConfig):
|
||||||
default_auto_field = 'django.db.models.BigAutoField'
|
name = 'apiserver.api'
|
||||||
name = 'api'
|
|
||||||
|
40
apiserver/apiserver/api/migrations/0001_initial.py
Normal file
40
apiserver/apiserver/api/migrations/0001_initial.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# Generated by Django 4.0.4 on 2022-04-27 23:47
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='CoolerData',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('time', models.DateTimeField()),
|
||||||
|
('cooler_id', models.CharField(blank=True, max_length=36)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='MinerData',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('time', models.DateTimeField()),
|
||||||
|
('miner_id', models.CharField(blank=True, max_length=36)),
|
||||||
|
('summary', models.JSONField()),
|
||||||
|
('fans', models.JSONField()),
|
||||||
|
('devdetails', models.JSONField()),
|
||||||
|
('version', models.JSONField()),
|
||||||
|
('devs', models.JSONField()),
|
||||||
|
('config', models.JSONField()),
|
||||||
|
('coin', models.JSONField()),
|
||||||
|
('pools', models.JSONField()),
|
||||||
|
('tunerstatus', models.JSONField()),
|
||||||
|
('temps', models.JSONField()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
@@ -0,0 +1,43 @@
|
|||||||
|
# Generated by Django 4.0.4 on 2022-06-23 21:30
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('api', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='coolerdata',
|
||||||
|
name='fan',
|
||||||
|
field=models.IntegerField(default=0),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='coolerdata',
|
||||||
|
name='max_temp',
|
||||||
|
field=models.DecimalField(decimal_places=4, default=0, max_digits=7),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='coolerdata',
|
||||||
|
name='pump',
|
||||||
|
field=models.IntegerField(default=0),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='coolerdata',
|
||||||
|
name='rad_temp',
|
||||||
|
field=models.DecimalField(decimal_places=4, default=0, max_digits=7),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='coolerdata',
|
||||||
|
name='tub_temp',
|
||||||
|
field=models.DecimalField(decimal_places=4, default=0, max_digits=7),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 4.0.4 on 2022-06-24 00:01
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('api', '0002_coolerdata_fan_coolerdata_max_temp_coolerdata_pump_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='minerdata',
|
||||||
|
name='json_version',
|
||||||
|
field=models.IntegerField(default=1),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
@@ -1,3 +1,28 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
# Create your models here.
|
class MinerData(models.Model):
|
||||||
|
time = models.DateTimeField()
|
||||||
|
miner_id = models.CharField(max_length=36, blank=True)
|
||||||
|
json_version = models.IntegerField()
|
||||||
|
|
||||||
|
summary = models.JSONField()
|
||||||
|
fans = models.JSONField()
|
||||||
|
devdetails = models.JSONField()
|
||||||
|
version = models.JSONField()
|
||||||
|
devs = models.JSONField()
|
||||||
|
config = models.JSONField()
|
||||||
|
coin = models.JSONField()
|
||||||
|
pools = models.JSONField()
|
||||||
|
tunerstatus = models.JSONField()
|
||||||
|
temps = models.JSONField()
|
||||||
|
|
||||||
|
class CoolerData(models.Model):
|
||||||
|
time = models.DateTimeField()
|
||||||
|
cooler_id = models.CharField(max_length=36, blank=True)
|
||||||
|
|
||||||
|
tub_temp = models.DecimalField(max_digits=7, decimal_places=4)
|
||||||
|
rad_temp = models.DecimalField(max_digits=7, decimal_places=4)
|
||||||
|
max_temp = models.DecimalField(max_digits=7, decimal_places=4)
|
||||||
|
|
||||||
|
fan = models.IntegerField()
|
||||||
|
pump = models.IntegerField()
|
||||||
|
@@ -1,7 +1,21 @@
|
|||||||
|
import logging
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from rest_framework import viewsets
|
from rest_framework import viewsets, views, mixins
|
||||||
from rest_framework import permissions
|
from rest_framework import permissions
|
||||||
from apiserver.api import serializers
|
from rest_framework.decorators import action
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from apiserver.api import serializers, models
|
||||||
|
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
|
Base = viewsets.GenericViewSet
|
||||||
|
List = mixins.ListModelMixin
|
||||||
|
Retrieve = mixins.RetrieveModelMixin
|
||||||
|
Create = mixins.CreateModelMixin
|
||||||
|
Update = mixins.UpdateModelMixin
|
||||||
|
Destroy = mixins.DestroyModelMixin
|
||||||
|
|
||||||
|
|
||||||
class UserViewSet(viewsets.ModelViewSet):
|
class UserViewSet(viewsets.ModelViewSet):
|
||||||
@@ -9,3 +23,52 @@ class UserViewSet(viewsets.ModelViewSet):
|
|||||||
serializer_class = serializers.UserSerializer
|
serializer_class = serializers.UserSerializer
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
permission_classes = [permissions.IsAuthenticated]
|
||||||
|
|
||||||
|
class DataViewSet(Base, List, Retrieve):
|
||||||
|
@action(detail=False, methods=['post'])
|
||||||
|
def push(self, request):
|
||||||
|
miner_data = request.data['miner_data']
|
||||||
|
cooler_data = request.data['cooler_data']
|
||||||
|
|
||||||
|
for miner_id, miner in miner_data.items():
|
||||||
|
time = miner['summary'][0]['STATUS'][0]['When']
|
||||||
|
|
||||||
|
models.MinerData.objects.update_or_create(
|
||||||
|
time=datetime.fromtimestamp(time, tz=timezone.utc),
|
||||||
|
miner_id=miner_id,
|
||||||
|
defaults=dict(
|
||||||
|
json_version=2,
|
||||||
|
summary=miner['summary'][0]['SUMMARY'][0],
|
||||||
|
fans=miner['fans'][0]['FANS'],
|
||||||
|
devdetails=miner['devdetails'][0]['DEVDETAILS'],
|
||||||
|
version=miner['version'][0]['VERSION'][0],
|
||||||
|
devs=miner['devs'][0]['DEVS'],
|
||||||
|
config=miner['config'][0]['CONFIG'][0],
|
||||||
|
coin=miner['coin'][0]['COIN'][0],
|
||||||
|
pools=miner['pools'][0]['POOLS'],
|
||||||
|
tunerstatus=miner['tunerstatus'][0]['TUNERSTATUS'][0],
|
||||||
|
temps=miner['temps'][0]['TEMPS'],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
time = cooler_data['time']
|
||||||
|
cooler_id = cooler_data['cooler_id']
|
||||||
|
|
||||||
|
models.CoolerData.objects.update_or_create(
|
||||||
|
time=datetime.fromtimestamp(time, tz=timezone.utc),
|
||||||
|
cooler_id=cooler_id,
|
||||||
|
defaults=dict(
|
||||||
|
tub_temp=cooler_data['tub_temp'],
|
||||||
|
rad_temp=cooler_data['rad_temp'],
|
||||||
|
max_temp=cooler_data['max_temp'],
|
||||||
|
fan=cooler_data['fan'],
|
||||||
|
pump=cooler_data['pump'],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
logging.info('Added {} miner data points from cooler {}.'.format(
|
||||||
|
len(miner_data),
|
||||||
|
cooler_id,
|
||||||
|
))
|
||||||
|
|
||||||
|
return Response(200)
|
||||||
|
|
||||||
|
@@ -10,6 +10,10 @@ For the full list of settings and their values, see
|
|||||||
https://docs.djangoproject.com/en/4.0/ref/settings/
|
https://docs.djangoproject.com/en/4.0/ref/settings/
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import logging.config
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
@@ -22,8 +26,8 @@ BASE_DIR = Path(__file__).resolve().parent.parent
|
|||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
SECRET_KEY = 'django-insecure-au(y+z)$-iy#(obif&ilg*_pn0j_+0u=q*p7h(3c-ii-euncwx'
|
SECRET_KEY = 'django-insecure-au(y+z)$-iy#(obif&ilg*_pn0j_+0u=q*p7h(3c-ii-euncwx'
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
DEBUG_ENV = os.environ.get('DEBUG', False)
|
||||||
DEBUG = True
|
DEBUG = DEBUG_ENV or False
|
||||||
|
|
||||||
ALLOWED_HOSTS = [
|
ALLOWED_HOSTS = [
|
||||||
'api.soak.stctech.ca',
|
'api.soak.stctech.ca',
|
||||||
@@ -40,6 +44,8 @@ INSTALLED_APPS = [
|
|||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
'rest_framework',
|
'rest_framework',
|
||||||
|
#'rest_framework.authtoken',
|
||||||
|
'apiserver.api',
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
@@ -127,3 +133,43 @@ STATIC_URL = 'static/'
|
|||||||
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
|
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
|
||||||
|
|
||||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||||
|
|
||||||
|
LOGGING = {
|
||||||
|
'version': 1,
|
||||||
|
'disable_existing_loggers': False,
|
||||||
|
'formatters': {
|
||||||
|
'medium': {
|
||||||
|
'format': '[%(asctime)s] [%(process)d] [%(levelname)7s] %(message)s'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'filters': {
|
||||||
|
},
|
||||||
|
'handlers': {
|
||||||
|
'console': {
|
||||||
|
'level': 'DEBUG',
|
||||||
|
'filters': [],
|
||||||
|
'class': 'logging.StreamHandler',
|
||||||
|
'formatter': 'medium'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'loggers': {
|
||||||
|
'gunicorn': {
|
||||||
|
'handlers': ['console'],
|
||||||
|
'level': 'DEBUG' if DEBUG else 'INFO',
|
||||||
|
'propagate': False,
|
||||||
|
},
|
||||||
|
'': {
|
||||||
|
'handlers': ['console'],
|
||||||
|
'level': 'DEBUG',
|
||||||
|
'propagate': True,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'root': {
|
||||||
|
'level': 'DEBUG' if DEBUG else 'INFO',
|
||||||
|
'handlers': ['console'],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
logging.config.dictConfig(LOGGING)
|
||||||
|
|
||||||
|
if DEBUG: logger.info('Debug mode ON')
|
||||||
|
logger.info('Test logging for each thread')
|
||||||
|
@@ -4,6 +4,7 @@ from apiserver.api import views
|
|||||||
|
|
||||||
router = routers.DefaultRouter()
|
router = routers.DefaultRouter()
|
||||||
router.register(r'users', views.UserViewSet)
|
router.register(r'users', views.UserViewSet)
|
||||||
|
router.register(r'data', views.DataViewSet, basename='data')
|
||||||
|
|
||||||
# Wire up our API using automatic URL routing.
|
# Wire up our API using automatic URL routing.
|
||||||
# Additionally, we include login URLs for the browsable API.
|
# Additionally, we include login URLs for the browsable API.
|
||||||
|
41
rpiserver/bosminer.py
Normal file
41
rpiserver/bosminer.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
|
||||||
|
async def bosminer_cmd(host, command, param=None):
|
||||||
|
reader, writer = await asyncio.open_connection(host, 4028)
|
||||||
|
|
||||||
|
payload = dict(command=command)
|
||||||
|
if param:
|
||||||
|
payload['parameter'] = param
|
||||||
|
|
||||||
|
message = json.dumps(payload)
|
||||||
|
writer.write(message.encode())
|
||||||
|
await writer.drain()
|
||||||
|
data = await reader.readuntil(separator=b'\00')
|
||||||
|
writer.close()
|
||||||
|
await writer.wait_closed()
|
||||||
|
|
||||||
|
return data[:-1].decode()
|
||||||
|
|
||||||
|
async def test():
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if len(sys.argv) == 3:
|
||||||
|
cmd = sys.argv[1]
|
||||||
|
param = sys.argv[2]
|
||||||
|
if len(sys.argv) == 2:
|
||||||
|
cmd = sys.argv[1]
|
||||||
|
param = None
|
||||||
|
else:
|
||||||
|
cmd = 'temps'
|
||||||
|
param = None
|
||||||
|
|
||||||
|
res = await bosminer_cmd('192.168.69.4', cmd, param)
|
||||||
|
j = json.loads(res)
|
||||||
|
print(json.dumps(j, indent=4))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
loop.run_until_complete(test())
|
||||||
|
loop.close()
|
4
rpiserver/data.py
Normal file
4
rpiserver/data.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
PROBES = {
|
||||||
|
'0218404f8bff': 'Rad',
|
||||||
|
'0218405068ff': 'Tub',
|
||||||
|
}
|
117
rpiserver/main.py
Normal file
117
rpiserver/main.py
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
import os
|
||||||
|
import logging
|
||||||
|
DEBUG = os.environ.get('DEBUG', False)
|
||||||
|
logging.basicConfig(
|
||||||
|
format='[%(asctime)s] %(levelname)s %(module)s/%(funcName)s - %(message)s',
|
||||||
|
level=logging.DEBUG if DEBUG else logging.INFO)
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from statistics import mean
|
||||||
|
from signal import *
|
||||||
|
import time
|
||||||
|
|
||||||
|
import w1therm
|
||||||
|
import relays
|
||||||
|
import data
|
||||||
|
import requests
|
||||||
|
|
||||||
|
HI_SETPOINT = 40.0
|
||||||
|
LO_SETPOINT = HI_SETPOINT - 5.0
|
||||||
|
|
||||||
|
PUMP_RELAY = relays.RELAY1
|
||||||
|
FAN_RELAY = relays.RELAY3
|
||||||
|
|
||||||
|
def controller_message(message):
|
||||||
|
payload = dict(misc=message)
|
||||||
|
r = requests.post('https://tbot.tannercollin.com/message', data=payload, timeout=10)
|
||||||
|
if r.status_code == 200:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
logging.exception('Unable to communicate with controller! Message: ' + message)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def set_fan_on():
|
||||||
|
relays.set_relay(FAN_RELAY, relays.RELAY_ON)
|
||||||
|
|
||||||
|
def set_fan_off():
|
||||||
|
relays.set_relay(FAN_RELAY, relays.RELAY_OFF)
|
||||||
|
|
||||||
|
def set_pump_on():
|
||||||
|
relays.set_relay(PUMP_RELAY, relays.RELAY_ON)
|
||||||
|
|
||||||
|
|
||||||
|
async def get_temp():
|
||||||
|
temps = await w1therm.get_temperatures()
|
||||||
|
if len(temps) != len(data.PROBES):
|
||||||
|
raise
|
||||||
|
|
||||||
|
temperature_log = []
|
||||||
|
for id_, temp in temps.items():
|
||||||
|
temperature_log.append('{}: {} C'.format(data.PROBES[id_], temp))
|
||||||
|
logging.info('Temperature probe ' + ', '.join(temperature_log))
|
||||||
|
|
||||||
|
temperature_list = list(temps.values())
|
||||||
|
temperature_mean = mean(temperature_list)
|
||||||
|
return temperature_mean
|
||||||
|
|
||||||
|
async def run_thermostat():
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
temperature_mean = await get_temp()
|
||||||
|
except:
|
||||||
|
logging.error('Problem reading temperature probes! Turning fan on and sleeping 60s.')
|
||||||
|
relays.set_relay(FAN_RELAY, relays.RELAY_ON)
|
||||||
|
await asyncio.sleep(60)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if temperature_mean > HI_SETPOINT:
|
||||||
|
logging.info('Turning fan on')
|
||||||
|
set_fan_on()
|
||||||
|
elif temperature_mean < LO_SETPOINT:
|
||||||
|
logging.info('Turning fan off')
|
||||||
|
set_fan_off()
|
||||||
|
|
||||||
|
await asyncio.sleep(10)
|
||||||
|
|
||||||
|
def run_on_exit(*args):
|
||||||
|
logging.info('Cryptosoak exiting, turning pump and fan on.')
|
||||||
|
controller_message('Cryptosoak exiting.')
|
||||||
|
set_pump_on()
|
||||||
|
set_fan_on()
|
||||||
|
exit()
|
||||||
|
|
||||||
|
async def feed_watchdog():
|
||||||
|
while True:
|
||||||
|
with open('/dev/watchdog', 'w') as wdt:
|
||||||
|
wdt.write('1')
|
||||||
|
await asyncio.sleep(5)
|
||||||
|
|
||||||
|
def init():
|
||||||
|
relays.init_relays()
|
||||||
|
set_pump_on()
|
||||||
|
|
||||||
|
for sig in (SIGABRT, SIGILL, SIGINT, SIGSEGV, SIGTERM):
|
||||||
|
signal(sig, run_on_exit)
|
||||||
|
logging.info('Signals initialized')
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
controller_message('Cryptosoak booting up...')
|
||||||
|
|
||||||
|
logging.info('Initialization complete')
|
||||||
|
|
||||||
|
await run_thermostat()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
init()
|
||||||
|
|
||||||
|
if not DEBUG:
|
||||||
|
logging.info('Waiting 60 seconds to boot...')
|
||||||
|
time.sleep(60)
|
||||||
|
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
loop.run_until_complete(main()).add_done_callback(run_on_exit)
|
||||||
|
if not DEBUG:
|
||||||
|
loop.run_until_complete(feed_watchdog())
|
||||||
|
loop.close()
|
||||||
|
|
41
rpiserver/relays.py
Normal file
41
rpiserver/relays.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import asyncio
|
||||||
|
import RPi.GPIO as GPIO
|
||||||
|
|
||||||
|
RELAY1 = 4
|
||||||
|
RELAY2 = 22
|
||||||
|
RELAY3 = 6
|
||||||
|
RELAY4 = 26
|
||||||
|
|
||||||
|
RELAY_ON = True
|
||||||
|
RELAY_OFF = False
|
||||||
|
|
||||||
|
RELAYS = [RELAY1, RELAY2, RELAY3, RELAY4]
|
||||||
|
|
||||||
|
def set_relay(r, state):
|
||||||
|
GPIO.output(r, state)
|
||||||
|
|
||||||
|
def all_off():
|
||||||
|
for r in RELAYS:
|
||||||
|
set_relay(r, RELAY_OFF)
|
||||||
|
|
||||||
|
def init_relays():
|
||||||
|
GPIO.setmode(GPIO.BCM)
|
||||||
|
GPIO.setwarnings(False)
|
||||||
|
|
||||||
|
for r in RELAYS:
|
||||||
|
GPIO.setup(r, GPIO.OUT)
|
||||||
|
|
||||||
|
all_off()
|
||||||
|
|
||||||
|
async def test():
|
||||||
|
for r in RELAYS:
|
||||||
|
set_relay(r, RELAY_ON)
|
||||||
|
await asyncio.sleep(0.5)
|
||||||
|
set_relay(r, RELAY_OFF)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
init_relays()
|
||||||
|
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
loop.run_until_complete(test())
|
||||||
|
loop.close()
|
37
rpiserver/requirements.txt
Normal file
37
rpiserver/requirements.txt
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
aiofiles==0.8.0
|
||||||
|
aiohttp==3.8.1
|
||||||
|
aiosignal==1.2.0
|
||||||
|
appdirs==1.4.4
|
||||||
|
async-timeout==4.0.2
|
||||||
|
attrs==21.4.0
|
||||||
|
certifi==2020.6.20
|
||||||
|
chardet==4.0.0
|
||||||
|
charset-normalizer==2.0.12
|
||||||
|
click==8.1.2
|
||||||
|
colorzero==1.1
|
||||||
|
dbus-python==1.2.16
|
||||||
|
distlib==0.3.1
|
||||||
|
distro==1.5.0
|
||||||
|
distro-info==1.0
|
||||||
|
filelock==3.0.12
|
||||||
|
frozenlist==1.3.0
|
||||||
|
gpiozero==1.6.2
|
||||||
|
idna==2.10
|
||||||
|
importlib-metadata==1.6.0
|
||||||
|
more-itertools==4.2.0
|
||||||
|
multidict==6.0.2
|
||||||
|
PyGObject==3.38.0
|
||||||
|
python-apt==2.2.1
|
||||||
|
requests==2.25.1
|
||||||
|
RPi.GPIO==0.7.0
|
||||||
|
six==1.16.0
|
||||||
|
spidev==3.5
|
||||||
|
ssh-import-id==5.10
|
||||||
|
supervisor==4.2.2
|
||||||
|
ufw==0.36
|
||||||
|
unattended-upgrades==0.1
|
||||||
|
urllib3==1.26.5
|
||||||
|
virtualenv==20.4.0+ds
|
||||||
|
w1thermsensor==2.0.0
|
||||||
|
yarl==1.7.2
|
||||||
|
zipp==1.0.0
|
22
rpiserver/w1therm.py
Normal file
22
rpiserver/w1therm.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import asyncio
|
||||||
|
from w1thermsensor import AsyncW1ThermSensor, Unit
|
||||||
|
|
||||||
|
async def get_temperatures():
|
||||||
|
temps = {}
|
||||||
|
|
||||||
|
for sensor in AsyncW1ThermSensor.get_available_sensors():
|
||||||
|
temps[sensor.id] = await sensor.get_temperature()
|
||||||
|
|
||||||
|
return temps
|
||||||
|
|
||||||
|
async def test():
|
||||||
|
temps = await get_temperatures()
|
||||||
|
|
||||||
|
for id_, temp in temps.items():
|
||||||
|
print('sensor', id_, ':' , temp, 'C')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
loop.run_until_complete(test())
|
||||||
|
loop.close()
|
||||||
|
|
Reference in New Issue
Block a user