diff --git a/.github/workflows/build_backend.yml b/.github/workflows/build_backend.yml index 5f458638..0feb5584 100644 --- a/.github/workflows/build_backend.yml +++ b/.github/workflows/build_backend.yml @@ -20,7 +20,7 @@ jobs: #python3 -m unittest test/cnn_test.py 2>&1 | tee test-reports/test_report.txt echo "test complete" - run: | - export PYTHONPATH=./coderbot:./stub:./test + export PYTHONPATH=./stub:./coderbot:./test python3 coderbot/main.py > coderbot.log & sleep 30 apt-get install -y python3-venv @@ -28,11 +28,16 @@ jobs: python3 -m venv schemathesis . schemathesis/bin/activate pip install schemathesis - st run --endpoint '^(?!(\/api\/v1\/video\/stream|\/api\/v1\/control\/move|\/api\/v1\/video\/rec|\/api\/v1\/video\/stop)$).*$' --hypothesis-max-examples=10 --request-timeout=20 http://localhost:5000/api/v1/openapi.json + st run --endpoint 'activities' --hypothesis-max-examples=10 --request-timeout=20 http://localhost:5000/api/v1/openapi.json + st run --endpoint 'media' --hypothesis-max-examples=10 --request-timeout=20 http://localhost:5000/api/v1/openapi.json + st run --endpoint 'control/speak' --hypothesis-max-examples=10 --request-timeout=20 http://localhost:5000/api/v1/openapi.json + st run --endpoint 'control/stop' --hypothesis-max-examples=10 --request-timeout=20 http://localhost:5000/api/v1/openapi.json + st run --endpoint 'music' --hypothesis-max-examples=10 --request-timeout=20 http://localhost:5000/api/v1/openapi.json + st run --endpoint 'programs' --hypothesis-max-examples=10 --request-timeout=20 http://localhost:5000/api/v1/openapi.json echo "openapi test complete" release-backend: - #needs: [test] + needs: [test] runs-on: ubuntu-latest steps: - name: Docker meta diff --git a/coderbot/activity.py b/coderbot/activity.py index 71f71a71..f2864c07 100644 --- a/coderbot/activity.py +++ b/coderbot/activity.py @@ -1,14 +1,12 @@ from tinydb import TinyDB, Query -from tinydb.operations import delete -import json # Programs and Activities databases class Activities(): _instance = None - + @classmethod def get_instance(cls): - if cls._instance == None: + if cls._instance is None: cls._instance = Activities() return cls._instance @@ -22,15 +20,14 @@ def load(self, name, default): if len(activities) > 0: return activities[0] elif default is not None: - default_Activities = self.activities.search(self.query.default == True) if len(self.activities.search(self.query.default == True)) > 0: return self.activities.search(self.query.default == True)[0] - else: - return None + return None + return None def save(self, name, activity): # if saved activity is "default", reset existing default activity to "non-default" - if activity.get("default", False) == True: + if activity.get("default", False) is True: self.activities.update({'default': False}) if self.activities.search(self.query.name == name) == []: self.activities.insert(activity) @@ -41,10 +38,9 @@ def delete(self, name): activities = self.activities.search(self.query.name == name) if len(activities) > 0: activity = activities[0] - if activity.get("default", False) == True: + if activity.get("default", False) is True: self.activities.update({'default': True}, self.query.stock == True) self.activities.remove(self.query.name == activity["name"]) def list(self): return self.activities.all() - diff --git a/coderbot/api.py b/coderbot/api.py index 35c3827b..114fdaff 100644 --- a/coderbot/api.py +++ b/coderbot/api.py @@ -28,6 +28,7 @@ from audio import Audio from event import EventManager from coderbotTestUnit import run_test as runCoderbotTestUnit +from balena import Balena BUTTON_PIN = 16 @@ -95,7 +96,7 @@ def get_info(): backend_commit = "undefined" coderbot_version = "undefined" update_status = "ok" - kernel = 'undefined' + device = {} motors = 'undefined' try: @@ -107,11 +108,6 @@ def get_info(): except Exception: pass - try: - kernel = subprocess.check_output(["uname", "-r"]).decode('utf-8').replace('\n', '') - except Exception: - pass - try: encoder = bool(Config.read().get('encoder')) if(encoder): @@ -123,12 +119,16 @@ def get_info(): serial = get_serial() - return {'backend_commit': backend_commit, - 'coderbot_version': coderbot_version, - 'update_status': update_status, - 'kernel': kernel, - 'serial': serial, - 'motors': motors} + try: + device = Baleba.get_instance().device() + except Exception: + pass + return { 'backend_commit': device.get("commit"), + 'coderbot_version': coderbot_version, + 'update_status': device.get("status"), + 'kernel': device.get("os_version"), + 'serial': serial, + 'motors': motors } prog = None prog_engine = ProgramEngine.get_instance() @@ -161,7 +161,8 @@ def turn(body): def takePhoto(): try: cam.photo_take() - Audio.say(config.get("sound_shutter")) + audio_device.say(config.get("sound_shutter")) + return 200 except Exception as e: logging.warning("Error: %s", e) @@ -169,6 +170,7 @@ def recVideo(): try: cam.video_rec() audio_device.say(config.get("sound_shutter")) + return 200 except Exception as e: logging.warning("Error: %s", e) @@ -176,6 +178,7 @@ def stopVideo(): try: cam.video_stop() audio_device.say(config.get("sound_shutter")) + return 200 except Exception as e: logging.warning("Error: %s", e) @@ -184,24 +187,24 @@ def speak(body): locale = body.get("locale", "") logging.debug("say: " + text + " in: " + locale) audio_device.say(text, locale) + return 200 def reset(): - logging.debug("reset bot") - shutil.rmtree("data/*") - bot.restart() + Balena.get_instance().purge() + return 200 def halt(): - logging.debug("shutting down") audio_device.say(what=config.get("sound_stop")) - bot.halt() + Balena.get_instance().shutdown() + return 200 def restart(): - logging.debug("restarting bot") - bot.restart() + Balena.get_instance().restart() def reboot(): - logging.debug("rebooting") - bot.reboot() + audio_device.say(what=config.get("sound_stop")) + Balena.get_instance().reboot() + return 200 def video_stream(a_cam): while True: @@ -287,13 +290,14 @@ def info(): def restoreSettings(): Config.restore() - restart() + return restart() def loadSettings(): return Config.get() def saveSettings(body): Config.write(body) + return 200 def updateFromPackage(): os.system('sudo bash /home/pi/clean-update.sh') diff --git a/coderbot/balena/__init__.py b/coderbot/balena/__init__.py new file mode 100644 index 00000000..5b5c9f9f --- /dev/null +++ b/coderbot/balena/__init__.py @@ -0,0 +1,44 @@ +import os +from urllib.request import urlopen, Request +import json +import logging + +class Balena(): + _instance = None + + @classmethod + def get_instance(cls): + if cls._instance is None: + cls._instance = Balena() + return cls._instance + + def __init__(self): + self.supervisor_address = os.environ["BALENA_SUPERVISOR_ADDRESS"] + self.supervisor_key = os.environ["BALENA_SUPERVISOR_API_KEY"] + self.app_id_data = json.dumps({ "appId": os.environ["BALENA_APP_ID"] }).encode("utf-8") + self.headers = { 'Content-Type': 'application/json' } + + def purge(self): + logging.debug("reset bot") + req = Request(f'{self.supervisor_address}/v1/purge?apikey={self.supervisor_key}', data=self.app_id_data, headers=self.headers, method='POST') + return urlopen(req).read() + + def shutdown(self): + logging.debug("shutdown bot") + req = Request(f'{self.supervisor_address}/v1/shutdown?apikey={self.supervisor_key}', headers=self.headers, method='POST') + return urlopen(req).read() + + def restart(self): + logging.debug("restarting bot") + req = Request(f'{self.supervisor_address}/v1/restart?apikey={self.supervisor_key}', data=self.app_id_data, headers=self.headers, method='POST') + return urlopen(req).read() + + def reboot(self): + logging.debug("reboot bot") + req = Request(f'{self.supervisor_address}/v1/reboot?apikey={self.supervisor_key}', headers=self.headers, method='POST') + return urlopen(req).read() + + def device(self): + logging.debug("reboot bot", f'{self.supervisor_address}get?apikey={self.supervisor_key}') + req = Request(f'{self.supervisor_address}/device?apikey={self.supervisor_key}', headers=self.headers, method='GET') + return json.load(urlopen(req)) diff --git a/coderbot/coderbot.py b/coderbot/coderbot.py index b28a1894..79547704 100644 --- a/coderbot/coderbot.py +++ b/coderbot/coderbot.py @@ -23,7 +23,7 @@ import logging import pigpio import sonar -import hw.mpu +from hw import mpu from rotary_encoder.wheelsaxel import WheelsAxel # GPIO @@ -268,13 +268,3 @@ def _cb_button(self, gpio, level, tick): logging.info("pushed: %d, %d", level, tick) cb() - def halt(self): - logging.info("halt requested") - pass - - def restart(self): - sys.exit() - - def reboot(self): - logging.info("reboot requested") - diff --git a/coderbot/hw/__init__.py b/coderbot/hw/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/coderbot/hw/mpu.py b/coderbot/hw/mpu.py index 5f266102..702dab45 100644 --- a/coderbot/hw/mpu.py +++ b/coderbot/hw/mpu.py @@ -1,4 +1,4 @@ -from hw import lsm9ds1 +from . import lsm9ds1 import time class AccelGyroMag: diff --git a/coderbot/main.py b/coderbot/main.py index 2071940e..45161004 100644 --- a/coderbot/main.py +++ b/coderbot/main.py @@ -5,22 +5,19 @@ import os import logging import logging.handlers -import subprocess import picamera import connexion -from flask import (send_from_directory, redirect) - from flask_cors import CORS -from coderbot import CoderBot from camera import Camera from motion import Motion from audio import Audio -from program import ProgramEngine, Program +from program import ProgramEngine from config import Config from cnn.cnn_manager import CNNManager from event import EventManager +from coderbot import CoderBot # Logging configuration logger = logging.getLogger() diff --git a/coderbot/program.py b/coderbot/program.py index 81581c4b..19e5c145 100644 --- a/coderbot/program.py +++ b/coderbot/program.py @@ -34,7 +34,7 @@ import event import music import musicPackages -import hw.atmega328p +from hw.atmega328p import ATMega328 PROGRAM_PATH = "./data/" PROGRAM_PREFIX = "program_" @@ -66,7 +66,7 @@ def get_music(): return music.Music.get_instance(musicPackageManager) def get_atmega(): - return atmega328p.ATMega328.get_instance() + return ATMega328.get_instance() class ProgramEngine: diff --git a/defaults/config.json b/defaults/config.json index 92aa1bdc..a93f77f4 100644 --- a/defaults/config.json +++ b/defaults/config.json @@ -38,7 +38,7 @@ "hw_version":"5", "audio_volume_level":"100", "wifi_mode":"ap", - "wifi_ssid":"coderbot_CHANGEMEATFIRSTRUN", + "wifi_ssid":"coderbot", "wifi_psk":"coderbot", "packages_installed":"", "admin_password":"", diff --git a/docker/Dockerfile b/docker/Dockerfile index d2057c54..f2ee6362 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -64,4 +64,4 @@ ADD docker/scripts/*.sh /tmp/. RUN /tmp/install_generic_cnn_models.sh RUN /tmp/install_lib_firmware.sh -ENTRYPOINT cd /coderbot && python3 coderbot/main.py \ No newline at end of file +ENTRYPOINT cd /coderbot && modprobe i2c-dev && python3 coderbot/main.py diff --git a/stub/balena/__init__.py b/stub/balena/__init__.py new file mode 100644 index 00000000..fe88a02b --- /dev/null +++ b/stub/balena/__init__.py @@ -0,0 +1,26 @@ +class Balena(): + _instance = None + + @classmethod + def get_instance(cls): + if cls._instance is None: + cls._instance = Balena() + return cls._instance + + def __init__(self): + pass + + def purge(self): + return "" + + def shutdown(self): + return "" + + def restart(self): + return "" + + def reboot(self): + return "" + + def device(self): + return {}
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: