Skip to content

Commit

Permalink
feat(sound): SoundPlayAudioEvent action for playing an audio sample…
Browse files Browse the repository at this point in the history
… with type of `Sequence[int]`

feat(voice): add new service voice with `VoiceReadTextAction`, it uses orca service from picovocie to read text with human voice
feat(notification): read the extra information of the notification when opened
feat(ssh): force password change after first login for temporarily created accounts
  • Loading branch information
sassanh committed Apr 20, 2024
1 parent f7897c3 commit 7bbfd55
Show file tree
Hide file tree
Showing 27 changed files with 547 additions and 158 deletions.
17 changes: 7 additions & 10 deletions .github/workflows/integration_delivery.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ jobs:
- uses: actions/checkout@v4
name: Checkout

- name: System Dependencies
run: |
sudo apt-get update -y
sudo apt-get install -y portaudio19-dev
- name: Load Cached Poetry
id: cached-poetry
uses: actions/cache@v4
Expand Down Expand Up @@ -131,7 +136,7 @@ jobs:
- name: Run Tests
run: |
mkdir -p $HOME/.kivy/mods
poetry run poe test --make-screenshots --cov-report=xml --cov-report=html -n auto --log-level=DEBUG
POETRY_VIRTUALENVS_OPTIONS_SYSTEM_SITE_PACKAGES=true poetry run poe test --make-screenshots --cov-report=xml --cov-report=html -n auto --log-level=DEBUG
- name: Collect Window Screenshots
uses: actions/upload-artifact@v4
Expand Down Expand Up @@ -265,7 +270,7 @@ jobs:
strategy:
fail-fast: false
matrix:
suffix: ['lite', '', 'full']
suffix: ['lite', '']
steps:
- run: echo Building amd64-${{ matrix.suffix }} image

Expand Down Expand Up @@ -404,14 +409,6 @@ jobs:
name: ubo_app-${{ needs.build.outputs.version }}-bookworm-arm64.img.gz
path: artifacts

- name: Procure Full Image
uses: actions/download-artifact@v4
with:
name:
ubo_app-${{ needs.build.outputs.version
}}-bookworm-full-arm64.img.gz
path: artifacts

- name: Procure Wheel
uses: actions/download-artifact@v4
with:
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@
- build(packer): mount the first partition of the image in `/boot/firmware` instead
of `/boot` to be compatible with the new linux kernel
- ci(github): download and cache images as it is the slowest part of the build
- feat(sound): `SoundPlayAudioEvent` action for playing an audio sample with type
of `Sequence[int]`
- feat(voice): add new service voice with `VoiceReadTextAction`, it uses orca service
from picovocie to read text with human voice
- feat(notification): read the extra information of the notification when opened
- feat(ssh): force password change after first login for temporarily created accounts

## Version 0.12.6

Expand Down
256 changes: 145 additions & 111 deletions poetry.lock

Large diffs are not rendered by default.

11 changes: 7 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ priority = "primary"
python = "^3.11"
psutil = "^5.9.8"
ubo-gui = [
{ version = "^0.10.6", markers = "extra=='default'", extras = [
{ version = "^0.10.7", markers = "extra=='default'", extras = [
"default",
] },
{ version = "^0.10.6", markers = "extra=='dev'", extras = [
{ version = "^0.10.7", markers = "extra=='dev'", extras = [
"dev",
] },
]
Expand All @@ -39,22 +39,24 @@ adafruit-circuitpython-veml7700 = "^1.1.22"
docker = "^7.0.0"
python-dotenv = "^1.0.1"
sentry-sdk = "^1.43.0"
pvorca = "^0.1.4"

[tool.poetry.group.dev]
optional = true

[tool.poetry.group.dev.dependencies]
poethepoet = "^0.24.4"
pyright = "^1.1.358"
pyright = "^1.1.359"
pytest = "^8.0.0"
pytest-asyncio = "^0.23.5.post1"
pytest-cov = "^4.1.0"
pytest-timeout = "^2.3.1"
pytest-xdist = "^3.5.0"
ruff = "^0.3.7"
ruff = "^0.4.1"
tenacity = "^8.2.3"
toml = "^0.10.2"
pytest-mock = "^3.14.0"
pyaudio = { version = "^0.2.14", markers = "platform_machine!='aarch64'" }

[tool.poetry.extras]
default = ["ubo-gui"]
Expand All @@ -80,6 +82,7 @@ args = [
{ name = "deps", type = "boolean" },
{ name = "run", type = "boolean" },
{ name = "bootstrap", type = "boolean" },
{ name = "env", type = "boolean" },
]
cmd = "scripts/deploy.sh"

Expand Down
17 changes: 11 additions & 6 deletions scripts/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,22 @@ LATEST_VERSION=$(basename $(ls -rt dist/*.whl | tail -n 1))
deps=${deps:-"False"}
bootstrap=${bootstrap:-"False"}
run=${run:-"False"}
env=${env:-"False"}

function run_on_pod() {
if [ $# -lt 1 ] || [ $# -gt 2 ]; then
echo "Usage: run_on_pod <command> [is_root]"
exit 1
return 1
fi
if [ $# -eq 1 ]; then
ssh ubo-development-pod "sudo XDG_RUNTIME_DIR=/run/user/\$(id -u ubo) -u ubo bash -c 'source \$HOME/.profile && source /etc/profile && source /opt/ubo/env/bin/activate && $1'"
exit 0
return 0
fi
if [ "$2" == "root" ]; then
ssh ubo-development-pod "sudo bash -c '$1'"
exit 0
return 0
else
return 1
fi
}

Expand All @@ -35,8 +38,10 @@ run_on_pod "pip install --upgrade --force-reinstal --no-deps /tmp/$LATEST_VERSIO
test "$bootstrap" == "True" &&
run_on_pod "/opt/ubo/env/bin/bootstrap; systemctl restart ubo-system.service" "root"

test "$env" == "True" &&
scp ubo_app/.dev.env ubo-development-pod:/tmp/ &&
run_on_pod "chown ubo:ubo /tmp/.dev.env" "root" &&
run_on_pod "mv /tmp/.dev.env /opt/ubo/env/lib/python3.11/site-packages/ubo_app/"

test "$run" == "True" &&
run_on_pod "systemctl --user restart ubo-app.service"

test "$env" == "True" &&
scp ubo_app/.dev.env /opt/ubo/env/lib/python3.11/site-packages/ubo_app/.env
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@
"Main",
"Settings",
"WiFi Settings",
"8d723104f77383c13458a748e9bb17bc"
"85776e9add84f39e71545a137a1d5006"
]
},
"status_icons": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@
"Main",
"Settings",
"WiFi Settings",
"8d723104f77383c13458a748e9bb17bc"
"85776e9add84f39e71545a137a1d5006"
]
},
"status_icons": {
Expand Down
6 changes: 5 additions & 1 deletion tests/fixtures/load_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class LoadServices(Protocol):
def __call__(
self: LoadServices,
service_ids: Sequence[str],
*,
timeout: float | None = None,
) -> None: ...

@overload
Expand All @@ -33,6 +35,7 @@ def __call__(
service_ids: Sequence[str],
*,
run_async: Literal[True],
timeout: float | None = None,
) -> Coroutine[None, None, None]: ...


Expand All @@ -45,12 +48,13 @@ def load_services_and_wait(
service_ids: Sequence[str],
*,
run_async: bool = False,
timeout: float | None = None,
) -> Coroutine[None, None, None] | None:
from ubo_app.load_services import load_services

load_services(service_ids)

@wait_for(run_async=cast(Literal[True], run_async))
@wait_for(run_async=cast(Literal[True], run_async), timeout=timeout)
def check() -> None:
for service_id in service_ids:
assert any(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"queue": []
},
"docker": {
"_id": "8d723104f77383c13458a748e9bb17bc",
"_id": "85776e9add84f39e71545a137a1d5006",
"home_assistant": {
"container_ip": null,
"docker_id": null,
Expand Down Expand Up @@ -251,6 +251,39 @@
"is_short": false,
"label": "SSH"
},
{
"background_color": "#68B7FF",
"color": [
1,
1,
1,
1
],
"icon": null,
"is_short": false,
"label": "Voice",
"sub_menu": {
"heading": "󰔊",
"items": [
{
"action": "",
"background_color": "#68B7FF",
"color": [
1,
1,
1,
1
],
"icon": "󰐲",
"is_short": false,
"label": "Access Token"
}
],
"placeholder": null,
"sub_heading": "Set the access token for picovoice service",
"title": "Voice Settings"
}
},
{
"background_color": "#68B7FF",
"color": [
Expand Down Expand Up @@ -425,6 +458,7 @@
"serial_number": "<not-available>",
"update_status": "up_to_date"
},
"voice": {},
"wifi": {
"connections": [],
"current_connection": null,
Expand Down
3 changes: 2 additions & 1 deletion tests/integration/test_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
'sensors',
'docker',
'ssh',
'voice',
]


Expand All @@ -40,7 +41,7 @@ async def test_all_services_register(

app = MenuApp()
app_context.set_app(app)
load_services(ALL_SERVICES_IDS)
load_services(ALL_SERVICES_IDS, timeout=10)
await stability()
store_snapshot.take()
window_snapshot.take()
4 changes: 4 additions & 0 deletions tests/monkeypatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ async def fake_create_subprocess_exec(
@pytest.fixture(autouse=True)
def _monkeypatch(monkeypatch: pytest.MonkeyPatch) -> None:
"""Mock external resources."""
from ubo_app.utils.fake import Fake

random.seed(0)
tracemalloc.start()

Expand All @@ -229,6 +231,8 @@ def _monkeypatch(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr('importlib.metadata.version', lambda _: '0.0.0')
monkeypatch.setattr('ubo_app.constants.STORE_GRACE_TIME', 0.1)

sys.modules['pyaudio'] = Fake()

_monkeypatch_socket(monkeypatch)
_monkeypatch_psutil(monkeypatch)
_monkeypatch_docker(monkeypatch)
Expand Down
2 changes: 2 additions & 0 deletions ubo_app/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
# each time a UUID is generated.
DEBUG_MODE_TEST_UUID = strtobool(os.environ.get('UBO_DEBUG_TEST_UUID', 'False')) == 1

PICOVOICE_API_KEY = os.environ.get('PICOVOICE_API_KEY', None)

DEBUG_MODE_DOCKER = strtobool(os.environ.get('UBO_DEBUG_DOCKER', 'False')) == 1
DOCKER_PREFIX = os.environ.get('UBO_DOCKER_PREFIX', '')
DOCKER_INSTALLATION_LOCK_FILE = Path('/var/run/ubo/docker_installation.lock')
8 changes: 7 additions & 1 deletion ubo_app/menu_app/menu_central.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
NotificationsClearAction,
NotificationsDisplayEvent,
)
from ubo_app.store.services.voice import VoiceReadTextAction

from .home_page import HomePage

Expand Down Expand Up @@ -130,7 +131,12 @@ def display_notification(
)

application.bind(
on_info=lambda _: self.menu_widget.open_application(info_application),
on_info=lambda _: (
dispatch(
VoiceReadTextAction(text=notification.extra_information or ''),
),
self.menu_widget.open_application(info_application),
),
)

self.menu_widget.open_application(application)
Expand Down
Loading

0 comments on commit 7bbfd55

Please sign in to comment.