Skip to content

Commit

Permalink
feat: update menu showing current version and a button to update ubo-app
Browse files Browse the repository at this point in the history
feat: add update system service to automatically install an update in boot time
if it is already downloaded
feat: add install script
feat: setup polkit to let `ubo` user `reboot` and `poweroff`
refactor: improve `deploy.sh` so that it hasn't a hardcoded username
feat: assume the package is installed in `/opt/` instead of `/home/pi/`
refactor: move service related files in `store/` to `store/services/`
refactor: update to latest versions of `ubo-gui` and `python-redux`
  • Loading branch information
sassanh committed Jan 20, 2024
1 parent a5f63bf commit c390462
Show file tree
Hide file tree
Showing 48 changed files with 1,025 additions and 215 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## Version 0.8.0

- feat: update menu showing current version and a button to update ubo-app
- feat: add update system service to automatically install an update in boot time
if it is already downloaded
- feat: add install script
- feat: setup polkit to let `ubo` user `reboot` and `poweroff`
- refactor: improve `deploy.sh` so that it hasn't a hardcoded username
- feat: assume the package is installed in `/opt/` instead of `/home/pi/`
- refactor: move service related files in `store/` to `store/services/`
- refactor: update to latest versions of `ubo-gui` and `python-redux`

## Version 0.7.14

- refactor: make `create_task` functional for the main application just like its
Expand Down
39 changes: 27 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,37 @@ botting from that image, you can ignore this section.

- Python 3.9 or later.
- Run `raspi-config` -> Interface Options -> Enable SPI
- Install these packages:

```sh
sudo apt install pip virtualenv libmtdev libgl1 libegl1 libcap-dev \
python3-libcamera python3-alsaaudio python3-pyaudio libzbar0 \
--no-install-recommends
```

## 📦 Installation

Note that as part of the installation process, these debian packages are installed:

- pip
- virtualenv
- libmtdev
- libgl1
- libegl1
- libcap-dev
- python3-libcamera
- python3-alsaaudio
- python3-pyaudio
- libzbar0

Also be aware that ubo-app only installs in `/opt/ubo` and it is not customizable
at the moment.

---

⚠️ **Executing scripts directly from the internet with root privileges poses a significant
security risk. It's generally a good practice to ensure you understand the script's
content before running it.**

---

To install ubo, run this command in a terminal shell:

```bash
virtualenv --system-site-packages ubo-app
source ubo-app/bin/activate
pip install ubo-app
# Run this if you want to run it automatically when RPi boots
sudo ubo-app/bin/ubo install_services
curl -sSL https://raw.githubusercontent.com/ubopod/ubo-app/main/ubo_app/system_services/install.sh | sudo bash
```

## 🤝 Contributing
Expand Down
453 changes: 427 additions & 26 deletions poetry.lock

Large diffs are not rendered by default.

16 changes: 11 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "ubo-app"
version = "0.7.14"
version = "0.8.0"
description = "Ubo main app, running on device initialization. A platform for running other apps."
authors = ["Sassan Haradji <[email protected]>"]
license = "Apache-2.0"
Expand All @@ -18,24 +18,29 @@ priority = "primary"
python = "^3.11"
psutil = "^5.9.6"
ubo-gui = [
{ version = "^0.7.7" },
{ version = "^0.7.7", markers = "extra=='dev'", extras = [
{ version = "^0.7.9", markers = "extra=='default'", extras = [
'default',
] },
{ version = "^0.7.9", markers = "extra=='dev'", extras = [
'dev',
] },
]
headless-kivy-pi = [
{ version = "^0.5.12" },
{ version = "^0.5.12", markers = "extra=='default'", extras = [
'default',
] },
{ version = "^0.5.12", markers = "extra=='dev'", extras = [
'dev',
] },
]
python-redux = "^0.9.12"
python-redux = "^0.9.13"
pyzbar = "^0.1.9"
sdbus-networkmanager = { version = "^2.0.0", markers = "platform_machine=='aarch64'" }
rpi_ws281x = { version = "^5.0.0", markers = "platform_machine=='aarch64'" }
python-debouncer = "^0.1.3"
adafruit-circuitpython-neopixel = "^6.3.11"
pulsectl = "^23.5.2"
aiohttp = "^3.9.1"

[tool.poetry.group.dev]
optional = true
Expand All @@ -45,6 +50,7 @@ pyright = "^1.1.342"
ruff = "^0.1.9"

[tool.poetry.extras]
default = ['ubo-gui', 'headless-kivy-pi']
dev = ['ubo-gui', 'headless-kivy-pi']

[tool.poetry.scripts]
Expand Down
6 changes: 3 additions & 3 deletions scripts/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ poetry build
LATEST_VERSION=$(basename $(ls -rt dist/*.whl | tail -n 1))

scp dist/$LATEST_VERSION pi@ubo-development-pod:/tmp/
test "$deps" == "True" && ssh pi@ubo-development-pod "source ubo-app/bin/activate; pip install --upgrade /tmp/$LATEST_VERSION[dev]"
ssh pi@ubo-development-pod "source \$HOME/.profile && source /etc/profile && source ubo-app/bin/activate && pip install --upgrade --force-reinstal --no-deps /tmp/$LATEST_VERSION[dev]"
test "$run" == "True" && ssh pi@ubo-development-pod "source ubo-app/bin/activate; sudo killall ubo -9; sudo \$(which ubo)"
test "$deps" == "True" && ssh pi@ubo-development-pod "sudo -u ubo bash -c 'source /opt/ubo/env/bin/activate; pip install --upgrade /tmp/$LATEST_VERSION[default]'"
ssh pi@ubo-development-pod "sudo -u ubo bash -c 'source \$HOME/.profile && source /etc/profile && source /opt/ubo/env/bin/activate && pip install --upgrade --force-reinstal --no-deps /tmp/$LATEST_VERSION[default]'"
test "$run" == "True" && ssh pi@ubo-development-pod "sudo service ubo-app restart"
2 changes: 2 additions & 0 deletions ubo_app/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import os
from distutils.util import strtobool

USERNAME = 'ubo'
INSTALLATION_PATH = '/opt/ubo'
DEBUG_MODE = strtobool(os.environ.get('UBO_DEBUG', 'False')) == 1
SERVICES_PATH = (
os.environ.get('UBO_SERVICES_PATH', '').split(':')
Expand Down
9 changes: 4 additions & 5 deletions ubo_app/menu_central.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@
from ubo_gui.page import PageWidget
from ubo_gui.volume import VolumeWidget

from ubo_app.constants import DEBUG_MODE
from ubo_app.store.keypad import Key, KeypadKeyPressEvent
from ubo_app.store.main import SetMenuPathAction
from ubo_app.store.notifications import (
from ubo_app.store.services.keypad import Key, KeypadKeyPressEvent
from ubo_app.store.services.notifications import (
NotificationDisplayType,
NotificationsClearAction,
NotificationsDisplayEvent,
)
from ubo_app.utils.async_ import create_task

from .store import autorun, dispatch, subscribe_event

Expand Down Expand Up @@ -132,8 +132,7 @@ async def sync_current_menu(menu: Menu | None) -> None:
return
Clock.schedule_once(lambda _: self.menu_widget.set_root_menu(menu))

create_task(sync_current_menu.value)
sync_current_menu.subscribe(lambda task: create_task(task))
sync_current_menu.subscribe(create_task)

def handle_title_change(_: MenuWidget, title: str) -> None:
self.root.title = title
Expand Down
4 changes: 2 additions & 2 deletions ubo_app/services/0-camera/reducer.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
ReducerResult,
)

from ubo_app.store.camera import (
from ubo_app.store.services.camera import (
CameraAction,
CameraEvent,
CameraStartViewfinderAction,
Expand All @@ -19,7 +19,7 @@
CameraStopViewfinderAction,
CameraStopViewfinderEvent,
)
from ubo_app.store.keypad import Key, KeypadAction
from ubo_app.store.services.keypad import Key, KeypadAction

Action = InitAction | CameraAction

Expand Down
2 changes: 1 addition & 1 deletion ubo_app/services/0-camera/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

from ubo_app.logging import logger
from ubo_app.store import dispatch, subscribe_event
from ubo_app.store.camera import (
from ubo_app.store.services.camera import (
CameraBarcodeAction,
CameraStartViewfinderEvent,
CameraStopViewfinderEvent,
Expand Down
2 changes: 1 addition & 1 deletion ubo_app/services/0-ethernet/ethernet_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from threading import current_thread
from typing import TYPE_CHECKING, Any, Coroutine, TypeVar

from ubo_app.store.ethernet import GlobalEthernetState
from ubo_app.store.services.ethernet import GlobalEthernetState
from ubo_app.utils import IS_RPI
from ubo_app.utils.fake import Fake

Expand Down
2 changes: 1 addition & 1 deletion ubo_app/services/0-ethernet/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from ethernet_manager import get_ethernet_device, get_ethernet_device_state

from ubo_app.store import dispatch
from ubo_app.store.ethernet import GlobalEthernetState
from ubo_app.store.services.ethernet import GlobalEthernetState
from ubo_app.store.status_icons import StatusIconsRegisterAction
from ubo_app.utils.async_ import create_task

Expand Down
2 changes: 1 addition & 1 deletion ubo_app/services/0-ip/reducer.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
ReducerResult,
)

from ubo_app.store.ip import (
from ubo_app.store.services.ip import (
IpState,
IpUpdateAction,
IpUpdateRequestAction,
Expand Down
38 changes: 14 additions & 24 deletions ubo_app/services/0-ip/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from ubo_app.store import autorun, dispatch, subscribe_event
from ubo_app.store.app import RegisterSettingAppAction
from ubo_app.store.ip import (
from ubo_app.store.services.ip import (
IpNetworkInterface,
IpUpdateAction,
IpUpdateRequestAction,
Expand Down Expand Up @@ -82,25 +82,21 @@ async def check_connection() -> bool:
await asyncio.sleep(1)
if is_connected():
dispatch(
[
IpUpdateRequestAction(),
StatusIconsRegisterAction(
icon='public',
priority=INTERNET_STATE_ICON_PRIORITY,
id=INTERNET_STATE_ICON_ID,
),
],
IpUpdateRequestAction(),
StatusIconsRegisterAction(
icon='public',
priority=INTERNET_STATE_ICON_PRIORITY,
id=INTERNET_STATE_ICON_ID,
),
)
else:
dispatch(
[
IpUpdateRequestAction(),
StatusIconsRegisterAction(
icon='public_off',
priority=INTERNET_STATE_ICON_PRIORITY,
id=INTERNET_STATE_ICON_ID,
),
],
IpUpdateRequestAction(),
StatusIconsRegisterAction(
icon='public_off',
priority=INTERNET_STATE_ICON_PRIORITY,
id=INTERNET_STATE_ICON_ID,
),
)


Expand All @@ -115,13 +111,7 @@ async def check_connection() -> bool:


def init_service() -> None:
dispatch(
[
RegisterSettingAppAction(
menu_item=IpMainMenu,
),
],
)
dispatch(RegisterSettingAppAction(menu_item=IpMainMenu))
create_task(check_connection())

subscribe_event(
Expand Down
4 changes: 2 additions & 2 deletions ubo_app/services/0-keyboard/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@

from kivy.core.window import Keyboard, Window, WindowBase

from ubo_app.store.keypad import (
from ubo_app.store.services.keypad import (
Key,
KeypadKeyPressAction,
)
from ubo_app.store.sound import (
from ubo_app.store.services.sound import (
SoundDevice,
SoundToggleMuteStatusAction,
)
Expand Down
6 changes: 3 additions & 3 deletions ubo_app/services/0-keypad/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
from typing import TYPE_CHECKING, Literal

import board
from redux import Immutable
from immutable import Immutable

from ubo_app.store.keypad import Key, KeypadKeyPressAction
from ubo_app.store.sound import SoundDevice, SoundSetMuteStatusAction
from ubo_app.store.services.keypad import Key, KeypadKeyPressAction
from ubo_app.store.services.sound import SoundDevice, SoundSetMuteStatusAction

INT_EXPANDER = 5 # GPIO PIN index that receives interrupt from AW9523

Expand Down
6 changes: 3 additions & 3 deletions ubo_app/services/0-notifications/reducer.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
ReducerResult,
)

from ubo_app.store.notifications import (
from ubo_app.store.services.notifications import (
Importance,
NotificationDisplayType,
NotificationsAction,
Expand All @@ -22,8 +22,8 @@
NotificationsDisplayEvent,
NotificationsState,
)
from ubo_app.store.rgb_ring import RgbRingBlinkAction
from ubo_app.store.sound import SoundPlayChimeAction
from ubo_app.store.services.rgb_ring import RgbRingBlinkAction
from ubo_app.store.services.sound import SoundPlayChimeAction

Action = InitAction | NotificationsAction
ResultAction = RgbRingBlinkAction | SoundPlayChimeAction
Expand Down
2 changes: 1 addition & 1 deletion ubo_app/services/0-rgb-ring/reducer.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
ReducerResult,
)

from ubo_app.store.rgb_ring import (
from ubo_app.store.services.rgb_ring import (
RgbRingAction,
RgbRingBlankAction,
RgbRingBlinkAction,
Expand Down
2 changes: 1 addition & 1 deletion ubo_app/services/0-rgb-ring/rgb_ring_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from ubo_app.logging import logger
from ubo_app.store import dispatch
from ubo_app.store.rgb_ring import RgbRingSetIsConnectedAction
from ubo_app.store.services.rgb_ring import RgbRingSetIsConnectedAction

LM_SOCKET_PATH = Path('/run/ubo').joinpath('ledmanagersocket.sock').as_posix()

Expand Down
6 changes: 4 additions & 2 deletions ubo_app/services/0-rgb-ring/rgb_ring_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
from adafruit_blinka.microcontroller.generic_micropython import Pin
from ubo_gui.menu import warnings

from ubo_app.constants import USERNAME

if TYPE_CHECKING:
from ubo_app.store.rgb_ring import Color
from ubo_app.store.services.rgb_ring import Color

BRIGHTNESS = 1.0
NUM_LEDS = 27
Expand Down Expand Up @@ -357,7 +359,7 @@ def run_command(self: LEDManager, incoming: Sequence[str]) -> None: # noqa: C90
t.start()

uid = pwd.getpwnam('root').pw_uid
gid = grp.getgrnam('pi').gr_gid
gid = grp.getgrnam(USERNAME).gr_gid

LM_SOCKET_PATH.unlink(missing_ok=True)

Expand Down
2 changes: 1 addition & 1 deletion ubo_app/services/0-rgb-ring/setup.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ruff: noqa: D100, D101, D102, D103, D104, D107, N999
from ubo_app.store import dispatch, subscribe_event
from ubo_app.store.rgb_ring import (
from ubo_app.store.services.rgb_ring import (
RgbRingCommandEvent,
RgbRingPulseAction,
RgbRingSetBrightnessAction,
Expand Down
Loading

0 comments on commit c390462

Please sign in to comment.