dosync 0.5.0__tar.gz → 0.6.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dosync-0.5.0 → dosync-0.6.1}/PKG-INFO +136 -4
- {dosync-0.5.0 → dosync-0.6.1}/README.md +135 -3
- {dosync-0.5.0 → dosync-0.6.1}/dosync/__init__.py +1 -1
- dosync-0.6.1/dosync/adapter_drafting.py +385 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/adapters/__init__.py +19 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/adapters/homeassistant.py +2 -1
- {dosync-0.5.0 → dosync-0.6.1}/dosync/adapters/matter.py +2 -1
- {dosync-0.5.0 → dosync-0.6.1}/dosync/adapters/mqtt.py +1 -1
- {dosync-0.5.0 → dosync-0.6.1}/dosync/adapters/notifications.py +1 -1
- {dosync-0.5.0 → dosync-0.6.1}/dosync/adapters/shelly.py +2 -1
- {dosync-0.5.0 → dosync-0.6.1}/dosync/adapters/wiz.py +12 -2
- {dosync-0.5.0 → dosync-0.6.1}/dosync/dashboard.html +263 -9
- {dosync-0.5.0 → dosync-0.6.1}/dosync/declarative.py +17 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/discoverers.py +12 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/discoverers_mdns.py +64 -3
- {dosync-0.5.0 → dosync-0.6.1}/dosync/discoverers_ssdp.py +51 -5
- {dosync-0.5.0 → dosync-0.6.1}/dosync/discovery.py +19 -2
- {dosync-0.5.0 → dosync-0.6.1}/dosync/manage.py +139 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/mcp_server.py +121 -2
- {dosync-0.5.0 → dosync-0.6.1}/dosync/models.py +45 -1
- {dosync-0.5.0 → dosync-0.6.1}/dosync/server.py +164 -6
- dosync-0.6.1/dosync/templates/adapter-draft-prompt.md +49 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync.egg-info/PKG-INFO +136 -4
- {dosync-0.5.0 → dosync-0.6.1}/dosync.egg-info/SOURCES.txt +5 -0
- {dosync-0.5.0 → dosync-0.6.1}/pyproject.toml +5 -1
- dosync-0.6.1/tests/test_adapter_drafting.py +676 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_adapters.py +63 -0
- dosync-0.6.1/tests/test_dashboard_tells_the_truth.py +206 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_deployment_env_contract.py +33 -0
- dosync-0.6.1/tests/test_device_identity.py +157 -0
- dosync-0.6.1/tests/test_documentation_is_navigable.py +189 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_no_operator_data.py +80 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_third_party_adapters.py +3 -1
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_transport_discoverers.py +182 -0
- dosync-0.5.0/tests/test_dashboard_tells_the_truth.py +0 -68
- {dosync-0.5.0 → dosync-0.6.1}/LICENSE +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/adapters/ble.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/adapters/declarative.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/adapters/mavlink.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/audit_backup.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/auth.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/auth_fastapi.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/cert_signing.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/certify.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/cli.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/composite_operations.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/config_reference.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/db.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/device_arbiter.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/ed25519_pure.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/examples/__init__.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/examples/declarative/3d-printer.yaml +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/examples/declarative/air-conditioner.yaml +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/examples/declarative/building-lighting.json +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/examples/declarative/industrial-conveyor.yaml +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/examples/declarative/light-generic.yaml +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/examples/declarative/television.yaml +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/executor.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/geo.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/hub.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/hub_monitor.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/lightweight.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/metrics.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/operation_guards.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/operation_supervisor.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/operations.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/paths.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/plugins.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/policies.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/policy_config.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/py.typed +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/reconciler.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/route_composer.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/security.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/spec_coverage.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync/validation.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync.egg-info/dependency_links.txt +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync.egg-info/entry_points.txt +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync.egg-info/requires.txt +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/dosync.egg-info/top_level.txt +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/setup.cfg +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_audit_archive.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_audit_backup.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_audit_chain_integrity.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_audit_provenance.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_auth.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_ble_adapter.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_certification_honesty.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_claim_state_machine.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_composite_operations.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_composite_orchestration.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_composition_kind_db.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_composition_kind_endpoint.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_composition_routing.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_db.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_declarative_adapters.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_declarative_quarantine.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_deployment_layout.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_device_health.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_device_heartbeat.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_direct_action_governance.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_discovery_adoption.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_drone_policies.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_ed25519_pure.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_emergency_preemption.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_env_loading_is_explicit.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_evaluation_metrics.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_event_loop_migration.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_explain_consistency.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_explain_resolve_parity.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_geo.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_ha_bridge_hygiene.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_hub_monitor.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_idempotency.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_independent_observation.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_integration_suite.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_lightweight_heartbeat.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_mavlink_adapter.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_mavlink_channels.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_mavlink_listener.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_mavlink_return_home.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_mavlink_single_reader.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_mavlink_telemetry_closure.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_mcp_dynamic_intents.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_mcp_partial_progress.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_metrics.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_models.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_multihub_endpoints.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_notification_templates.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_operation_guards.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_operation_supervisor.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_operations.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_operations_endpoints.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_operations_persistence.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_operations_wiring.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_panel_polish_2026_07_21.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_policies.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_policy_config.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_public_claims.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_pushed_verification.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_quickstart_is_runnable.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_reachability_cause.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_recall_benchmark_postpolicy.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_reconciler.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_resolution_wiring.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_resolver_scoring.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_resolver_semantics.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_route_composer.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_sensor_kind.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_server.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_simulation_is_declared.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_telemetry_bridge.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_universal_intent_contract.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_validation.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_validation_integration.py +0 -0
- {dosync-0.5.0 → dosync-0.6.1}/tests/test_wiring_audit.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dosync
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.1
|
|
4
4
|
Summary: The semantic layer between AI agents and physical devices
|
|
5
5
|
Author-email: Rodrigo Giuliani <rgiuliani@dosync.dev>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -194,7 +194,7 @@ DoSync earns its place in specific situations — and honestly gets in the way i
|
|
|
194
194
|
- Have a single device or one brand's ecosystem — you don't need a coordination layer.
|
|
195
195
|
- Don't need auditability or a policy layer.
|
|
196
196
|
|
|
197
|
-
**If the first list is you:** the fastest way in is the **[20-minute device tutorial](
|
|
197
|
+
**If the first list is you:** the fastest way in is the **[20-minute device tutorial](docs/DEVICE-INTEGRATION.md)** — build a device that senses, expresses a goal, and acts, with the full audit trail. Or open an [issue](https://github.com/giulianireg-spec/dosync-protocol/issues) describing what you're trying to coordinate and we'll tell you honestly whether DoSync fits.
|
|
198
198
|
|
|
199
199
|
---
|
|
200
200
|
|
|
@@ -249,6 +249,20 @@ Benchmark (Raspberry Pi 5, Python 3.11.2):
|
|
|
249
249
|
|
|
250
250
|
---
|
|
251
251
|
|
|
252
|
+
## Where to start
|
|
253
|
+
|
|
254
|
+
| You want to… | Go to |
|
|
255
|
+
|---|---|
|
|
256
|
+
| **run a hub and see your devices** | [Quick start](#quick-start), below — about five minutes, no terminal after the first command |
|
|
257
|
+
| **build a device that speaks the protocol** | [docs/DEVICE-INTEGRATION.md](docs/DEVICE-INTEGRATION.md) — needs Docker, a broker and Python |
|
|
258
|
+
| **implement DoSync yourself, or check conformance** | [spec/](spec/) — the wire format, the JSON schemas, and `certify.py` |
|
|
259
|
+
| **understand why it is built this way** | [DESIGN-PRINCIPLES.md](DESIGN-PRINCIPLES.md) |
|
|
260
|
+
| **know its scope, or who decides** | [docs/VISION.md](docs/VISION.md) · [GOVERNANCE.md](GOVERNANCE.md) |
|
|
261
|
+
|
|
262
|
+
Three of those four were reachable only by guessing. The one called `TUTORIAL.md`
|
|
263
|
+
sat in the repository root, where a reader looks first, and asked for Docker in
|
|
264
|
+
its first step.
|
|
265
|
+
|
|
252
266
|
## Quick start
|
|
253
267
|
|
|
254
268
|
### Install and run — five minutes, no hardware
|
|
@@ -283,6 +297,10 @@ Two things the rest of this page assumes that PowerShell does not provide:
|
|
|
283
297
|
`curl.exe`, or the PowerShell examples further down. `setup_pki.sh` is a shell
|
|
284
298
|
script and needs Git Bash or WSL.
|
|
285
299
|
|
|
300
|
+
If a control library for your hardware needs installing afterwards, a plain
|
|
301
|
+
`pip install` will not reach it — `pipx` keeps the hub in its own isolated
|
|
302
|
+
environment. See **pipx inject**, below.
|
|
303
|
+
|
|
286
304
|
</details>
|
|
287
305
|
|
|
288
306
|
### Then open the dashboard
|
|
@@ -502,6 +520,22 @@ The operator runs `pip install dosync-adapter-daikin` and the hub finds it. No
|
|
|
502
520
|
pull request here, and no promise from this project to maintain code for
|
|
503
521
|
hardware it has never seen — the publisher answers for their own adapter.
|
|
504
522
|
|
|
523
|
+
**If DoSync itself was installed with `pipx`, a plain `pip install` lands in
|
|
524
|
+
the wrong environment.** `pipx` deliberately isolates the hub in its own
|
|
525
|
+
virtual environment, separate from the system Python, so a vendor library
|
|
526
|
+
installed the ordinary way is invisible to it — the hub stays silent about
|
|
527
|
+
this exactly as it does about an uninstalled one, because from its side
|
|
528
|
+
there is no difference. Install into the hub's own environment instead:
|
|
529
|
+
|
|
530
|
+
```bash
|
|
531
|
+
pipx inject dosync dosync-adapter-daikin
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
This is not specific to any one vendor's product: it is how you add *any*
|
|
535
|
+
optional dependency — a control library, a third-party adapter package, a
|
|
536
|
+
protocol SDK — after installing DoSync with `pipx`. Whichever hardware you
|
|
537
|
+
own, `pipx inject dosync <package>` is the command, not `pip install`.
|
|
538
|
+
|
|
505
539
|
A third-party adapter runs inside the hub with the hub's permissions, so the hub
|
|
506
540
|
says so: it is logged at WARNING when loaded, recorded in the audit chain, and
|
|
507
541
|
reported as `kind: third_party` at `/v1/adapters` regardless of what the plugin
|
|
@@ -654,6 +688,104 @@ pytest # runs the full suite
|
|
|
654
688
|
dosync-hub --reload
|
|
655
689
|
```
|
|
656
690
|
|
|
691
|
+
The hub stops when the terminal closes. To keep it running across reboots, see
|
|
692
|
+
[Keeping the hub running](#keeping-the-hub-running).
|
|
693
|
+
|
|
694
|
+
---
|
|
695
|
+
|
|
696
|
+
## Keeping the hub running
|
|
697
|
+
|
|
698
|
+
Everything above starts a hub in a terminal, and it stops when that terminal
|
|
699
|
+
closes. Nothing in this project has explained how to change that — while the
|
|
700
|
+
repository has shipped a systemd unit at its root for months and this page
|
|
701
|
+
refers to *"your service"* as though you already had one. That gap is the
|
|
702
|
+
reason this section exists.
|
|
703
|
+
|
|
704
|
+
DoSync does not implement supervision on any platform. It delegates: to systemd
|
|
705
|
+
on Linux, to the task scheduler on Windows. What differs between them is how
|
|
706
|
+
much you have to write, not whether it works.
|
|
707
|
+
|
|
708
|
+
**Say once what is at stake:** a hub that governs physical actions and does not
|
|
709
|
+
come back after a power cut is a deployment decision with consequences. If a
|
|
710
|
+
lock, an alarm or a machine depends on it, this is not optional.
|
|
711
|
+
|
|
712
|
+
### Linux — systemd
|
|
713
|
+
|
|
714
|
+
`dosync.service` in the repository root is a template. Adjust the paths, then:
|
|
715
|
+
|
|
716
|
+
```bash
|
|
717
|
+
sudo cp dosync.service /etc/systemd/system/
|
|
718
|
+
sudo systemctl daemon-reload
|
|
719
|
+
sudo systemctl enable --now dosync
|
|
720
|
+
systemctl status dosync
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
**Keep secrets out of the unit.** It is a file people copy, and this one carried
|
|
724
|
+
a real Home Assistant token in a public repository until August 2026. Put them
|
|
725
|
+
in a drop-in that is not tracked:
|
|
726
|
+
|
|
727
|
+
```bash
|
|
728
|
+
sudo install -d -m 700 /etc/systemd/system/dosync.service.d
|
|
729
|
+
sudo tee /etc/systemd/system/dosync.service.d/local.conf >/dev/null <<'EOF'
|
|
730
|
+
[Service]
|
|
731
|
+
Environment="HA_TOKEN=your-token-here"
|
|
732
|
+
EOF
|
|
733
|
+
sudo chmod 600 /etc/systemd/system/dosync.service.d/local.conf
|
|
734
|
+
sudo systemctl daemon-reload && sudo systemctl restart dosync
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
systemd merges drop-ins over the unit, so the template never needs editing.
|
|
738
|
+
|
|
739
|
+
### Windows — Task Scheduler
|
|
740
|
+
|
|
741
|
+
*Verified on Windows 11 ARM64 in a virtual machine, Python 3.14, installed with
|
|
742
|
+
`pipx`.*
|
|
743
|
+
|
|
744
|
+
Run PowerShell **as administrator**:
|
|
745
|
+
|
|
746
|
+
```powershell
|
|
747
|
+
$exe = (Get-Command dosync-hub).Source
|
|
748
|
+
$db = "$env:USERPROFILE\.local\state\dosync\dosync.db"
|
|
749
|
+
|
|
750
|
+
$action = New-ScheduledTaskAction -Execute "cmd.exe" `
|
|
751
|
+
-Argument "/c set DOSYNC_DB=$db && `"$exe`""
|
|
752
|
+
$trigger = New-ScheduledTaskTrigger -AtStartup
|
|
753
|
+
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" `
|
|
754
|
+
-LogonType ServiceAccount -RunLevel Highest
|
|
755
|
+
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries `
|
|
756
|
+
-DontStopIfGoingOnBatteries -RestartCount 3 `
|
|
757
|
+
-RestartInterval (New-TimeSpan -Minutes 1)
|
|
758
|
+
|
|
759
|
+
Register-ScheduledTask -TaskName "DoSync Hub" -Action $action `
|
|
760
|
+
-Trigger $trigger -Principal $principal -Settings $settings
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
`-AtStartup` with `SYSTEM` means the hub comes back after a reboot without
|
|
764
|
+
anyone logging in — the closest equivalent to systemd. `-RestartCount` covers a
|
|
765
|
+
process that dies.
|
|
766
|
+
|
|
767
|
+
**`DOSYNC_DB` is not optional, and leaving it out fails silently.** A scheduled
|
|
768
|
+
task does not inherit your environment, so a hub started this way writes to
|
|
769
|
+
`C:\Windows\System32\config\systemprofile\` — a different database from the
|
|
770
|
+
one you used by hand. It starts perfectly, reports `devices: 0`, and looks like
|
|
771
|
+
your inventory was lost. Setting `DOSYNC_DB` points both at the same file;
|
|
772
|
+
running it by hand afterwards reads what the scheduled task wrote, with no
|
|
773
|
+
permission conflict.
|
|
774
|
+
|
|
775
|
+
Check it:
|
|
776
|
+
|
|
777
|
+
```powershell
|
|
778
|
+
curl.exe -s http://localhost:47200/v1/status | findstr db_path
|
|
779
|
+
Get-ScheduledTask -TaskName "DoSync Hub" | Get-ScheduledTaskInfo
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
`LastTaskResult: 267009` is `0x41301` — *the task is currently running*. That is
|
|
783
|
+
the healthy value here; `0` would mean it exited.
|
|
784
|
+
|
|
785
|
+
**NSSM** installs the hub as a real Windows service and is what a server
|
|
786
|
+
deployment would use. It is third-party software this project does not ship or
|
|
787
|
+
test, so it is named rather than recommended.
|
|
788
|
+
|
|
657
789
|
---
|
|
658
790
|
|
|
659
791
|
## What's built today
|
|
@@ -726,7 +858,7 @@ is implementable in a second language against the same certification suite —
|
|
|
726
858
|
both share the same author. A genuinely **independent** implementation
|
|
727
859
|
(different author or organization) is a tracked milestone for v1.0: a protocol
|
|
728
860
|
needs multiple independent implementations to become a standard. See the
|
|
729
|
-
[
|
|
861
|
+
[vision and scope](docs/VISION.md).
|
|
730
862
|
|
|
731
863
|
---
|
|
732
864
|
|
|
@@ -757,7 +889,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for development workflow, including the C
|
|
|
757
889
|
- [spec/DoSync-SPEC-v0.1.md](spec/DoSync-SPEC-v0.1.md) — full protocol specification
|
|
758
890
|
- [spec/RESOLVER-SPEC-v0.3.md](spec/RESOLVER-SPEC-v0.3.md) — resolver interface + external resolver protocol
|
|
759
891
|
- [DESIGN-PRINCIPLES.md](DESIGN-PRINCIPLES.md) — architectural decisions and rationale
|
|
760
|
-
- [COMPATIBILITY.md](COMPATIBILITY.md) — backward compatibility guarantees
|
|
892
|
+
- [COMPATIBILITY.md](docs/COMPATIBILITY.md) — backward compatibility guarantees
|
|
761
893
|
|
|
762
894
|
---
|
|
763
895
|
|
|
@@ -132,7 +132,7 @@ DoSync earns its place in specific situations — and honestly gets in the way i
|
|
|
132
132
|
- Have a single device or one brand's ecosystem — you don't need a coordination layer.
|
|
133
133
|
- Don't need auditability or a policy layer.
|
|
134
134
|
|
|
135
|
-
**If the first list is you:** the fastest way in is the **[20-minute device tutorial](
|
|
135
|
+
**If the first list is you:** the fastest way in is the **[20-minute device tutorial](docs/DEVICE-INTEGRATION.md)** — build a device that senses, expresses a goal, and acts, with the full audit trail. Or open an [issue](https://github.com/giulianireg-spec/dosync-protocol/issues) describing what you're trying to coordinate and we'll tell you honestly whether DoSync fits.
|
|
136
136
|
|
|
137
137
|
---
|
|
138
138
|
|
|
@@ -187,6 +187,20 @@ Benchmark (Raspberry Pi 5, Python 3.11.2):
|
|
|
187
187
|
|
|
188
188
|
---
|
|
189
189
|
|
|
190
|
+
## Where to start
|
|
191
|
+
|
|
192
|
+
| You want to… | Go to |
|
|
193
|
+
|---|---|
|
|
194
|
+
| **run a hub and see your devices** | [Quick start](#quick-start), below — about five minutes, no terminal after the first command |
|
|
195
|
+
| **build a device that speaks the protocol** | [docs/DEVICE-INTEGRATION.md](docs/DEVICE-INTEGRATION.md) — needs Docker, a broker and Python |
|
|
196
|
+
| **implement DoSync yourself, or check conformance** | [spec/](spec/) — the wire format, the JSON schemas, and `certify.py` |
|
|
197
|
+
| **understand why it is built this way** | [DESIGN-PRINCIPLES.md](DESIGN-PRINCIPLES.md) |
|
|
198
|
+
| **know its scope, or who decides** | [docs/VISION.md](docs/VISION.md) · [GOVERNANCE.md](GOVERNANCE.md) |
|
|
199
|
+
|
|
200
|
+
Three of those four were reachable only by guessing. The one called `TUTORIAL.md`
|
|
201
|
+
sat in the repository root, where a reader looks first, and asked for Docker in
|
|
202
|
+
its first step.
|
|
203
|
+
|
|
190
204
|
## Quick start
|
|
191
205
|
|
|
192
206
|
### Install and run — five minutes, no hardware
|
|
@@ -221,6 +235,10 @@ Two things the rest of this page assumes that PowerShell does not provide:
|
|
|
221
235
|
`curl.exe`, or the PowerShell examples further down. `setup_pki.sh` is a shell
|
|
222
236
|
script and needs Git Bash or WSL.
|
|
223
237
|
|
|
238
|
+
If a control library for your hardware needs installing afterwards, a plain
|
|
239
|
+
`pip install` will not reach it — `pipx` keeps the hub in its own isolated
|
|
240
|
+
environment. See **pipx inject**, below.
|
|
241
|
+
|
|
224
242
|
</details>
|
|
225
243
|
|
|
226
244
|
### Then open the dashboard
|
|
@@ -440,6 +458,22 @@ The operator runs `pip install dosync-adapter-daikin` and the hub finds it. No
|
|
|
440
458
|
pull request here, and no promise from this project to maintain code for
|
|
441
459
|
hardware it has never seen — the publisher answers for their own adapter.
|
|
442
460
|
|
|
461
|
+
**If DoSync itself was installed with `pipx`, a plain `pip install` lands in
|
|
462
|
+
the wrong environment.** `pipx` deliberately isolates the hub in its own
|
|
463
|
+
virtual environment, separate from the system Python, so a vendor library
|
|
464
|
+
installed the ordinary way is invisible to it — the hub stays silent about
|
|
465
|
+
this exactly as it does about an uninstalled one, because from its side
|
|
466
|
+
there is no difference. Install into the hub's own environment instead:
|
|
467
|
+
|
|
468
|
+
```bash
|
|
469
|
+
pipx inject dosync dosync-adapter-daikin
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
This is not specific to any one vendor's product: it is how you add *any*
|
|
473
|
+
optional dependency — a control library, a third-party adapter package, a
|
|
474
|
+
protocol SDK — after installing DoSync with `pipx`. Whichever hardware you
|
|
475
|
+
own, `pipx inject dosync <package>` is the command, not `pip install`.
|
|
476
|
+
|
|
443
477
|
A third-party adapter runs inside the hub with the hub's permissions, so the hub
|
|
444
478
|
says so: it is logged at WARNING when loaded, recorded in the audit chain, and
|
|
445
479
|
reported as `kind: third_party` at `/v1/adapters` regardless of what the plugin
|
|
@@ -592,6 +626,104 @@ pytest # runs the full suite
|
|
|
592
626
|
dosync-hub --reload
|
|
593
627
|
```
|
|
594
628
|
|
|
629
|
+
The hub stops when the terminal closes. To keep it running across reboots, see
|
|
630
|
+
[Keeping the hub running](#keeping-the-hub-running).
|
|
631
|
+
|
|
632
|
+
---
|
|
633
|
+
|
|
634
|
+
## Keeping the hub running
|
|
635
|
+
|
|
636
|
+
Everything above starts a hub in a terminal, and it stops when that terminal
|
|
637
|
+
closes. Nothing in this project has explained how to change that — while the
|
|
638
|
+
repository has shipped a systemd unit at its root for months and this page
|
|
639
|
+
refers to *"your service"* as though you already had one. That gap is the
|
|
640
|
+
reason this section exists.
|
|
641
|
+
|
|
642
|
+
DoSync does not implement supervision on any platform. It delegates: to systemd
|
|
643
|
+
on Linux, to the task scheduler on Windows. What differs between them is how
|
|
644
|
+
much you have to write, not whether it works.
|
|
645
|
+
|
|
646
|
+
**Say once what is at stake:** a hub that governs physical actions and does not
|
|
647
|
+
come back after a power cut is a deployment decision with consequences. If a
|
|
648
|
+
lock, an alarm or a machine depends on it, this is not optional.
|
|
649
|
+
|
|
650
|
+
### Linux — systemd
|
|
651
|
+
|
|
652
|
+
`dosync.service` in the repository root is a template. Adjust the paths, then:
|
|
653
|
+
|
|
654
|
+
```bash
|
|
655
|
+
sudo cp dosync.service /etc/systemd/system/
|
|
656
|
+
sudo systemctl daemon-reload
|
|
657
|
+
sudo systemctl enable --now dosync
|
|
658
|
+
systemctl status dosync
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
**Keep secrets out of the unit.** It is a file people copy, and this one carried
|
|
662
|
+
a real Home Assistant token in a public repository until August 2026. Put them
|
|
663
|
+
in a drop-in that is not tracked:
|
|
664
|
+
|
|
665
|
+
```bash
|
|
666
|
+
sudo install -d -m 700 /etc/systemd/system/dosync.service.d
|
|
667
|
+
sudo tee /etc/systemd/system/dosync.service.d/local.conf >/dev/null <<'EOF'
|
|
668
|
+
[Service]
|
|
669
|
+
Environment="HA_TOKEN=your-token-here"
|
|
670
|
+
EOF
|
|
671
|
+
sudo chmod 600 /etc/systemd/system/dosync.service.d/local.conf
|
|
672
|
+
sudo systemctl daemon-reload && sudo systemctl restart dosync
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
systemd merges drop-ins over the unit, so the template never needs editing.
|
|
676
|
+
|
|
677
|
+
### Windows — Task Scheduler
|
|
678
|
+
|
|
679
|
+
*Verified on Windows 11 ARM64 in a virtual machine, Python 3.14, installed with
|
|
680
|
+
`pipx`.*
|
|
681
|
+
|
|
682
|
+
Run PowerShell **as administrator**:
|
|
683
|
+
|
|
684
|
+
```powershell
|
|
685
|
+
$exe = (Get-Command dosync-hub).Source
|
|
686
|
+
$db = "$env:USERPROFILE\.local\state\dosync\dosync.db"
|
|
687
|
+
|
|
688
|
+
$action = New-ScheduledTaskAction -Execute "cmd.exe" `
|
|
689
|
+
-Argument "/c set DOSYNC_DB=$db && `"$exe`""
|
|
690
|
+
$trigger = New-ScheduledTaskTrigger -AtStartup
|
|
691
|
+
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" `
|
|
692
|
+
-LogonType ServiceAccount -RunLevel Highest
|
|
693
|
+
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries `
|
|
694
|
+
-DontStopIfGoingOnBatteries -RestartCount 3 `
|
|
695
|
+
-RestartInterval (New-TimeSpan -Minutes 1)
|
|
696
|
+
|
|
697
|
+
Register-ScheduledTask -TaskName "DoSync Hub" -Action $action `
|
|
698
|
+
-Trigger $trigger -Principal $principal -Settings $settings
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
`-AtStartup` with `SYSTEM` means the hub comes back after a reboot without
|
|
702
|
+
anyone logging in — the closest equivalent to systemd. `-RestartCount` covers a
|
|
703
|
+
process that dies.
|
|
704
|
+
|
|
705
|
+
**`DOSYNC_DB` is not optional, and leaving it out fails silently.** A scheduled
|
|
706
|
+
task does not inherit your environment, so a hub started this way writes to
|
|
707
|
+
`C:\Windows\System32\config\systemprofile\` — a different database from the
|
|
708
|
+
one you used by hand. It starts perfectly, reports `devices: 0`, and looks like
|
|
709
|
+
your inventory was lost. Setting `DOSYNC_DB` points both at the same file;
|
|
710
|
+
running it by hand afterwards reads what the scheduled task wrote, with no
|
|
711
|
+
permission conflict.
|
|
712
|
+
|
|
713
|
+
Check it:
|
|
714
|
+
|
|
715
|
+
```powershell
|
|
716
|
+
curl.exe -s http://localhost:47200/v1/status | findstr db_path
|
|
717
|
+
Get-ScheduledTask -TaskName "DoSync Hub" | Get-ScheduledTaskInfo
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
`LastTaskResult: 267009` is `0x41301` — *the task is currently running*. That is
|
|
721
|
+
the healthy value here; `0` would mean it exited.
|
|
722
|
+
|
|
723
|
+
**NSSM** installs the hub as a real Windows service and is what a server
|
|
724
|
+
deployment would use. It is third-party software this project does not ship or
|
|
725
|
+
test, so it is named rather than recommended.
|
|
726
|
+
|
|
595
727
|
---
|
|
596
728
|
|
|
597
729
|
## What's built today
|
|
@@ -664,7 +796,7 @@ is implementable in a second language against the same certification suite —
|
|
|
664
796
|
both share the same author. A genuinely **independent** implementation
|
|
665
797
|
(different author or organization) is a tracked milestone for v1.0: a protocol
|
|
666
798
|
needs multiple independent implementations to become a standard. See the
|
|
667
|
-
[
|
|
799
|
+
[vision and scope](docs/VISION.md).
|
|
668
800
|
|
|
669
801
|
---
|
|
670
802
|
|
|
@@ -695,7 +827,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for development workflow, including the C
|
|
|
695
827
|
- [spec/DoSync-SPEC-v0.1.md](spec/DoSync-SPEC-v0.1.md) — full protocol specification
|
|
696
828
|
- [spec/RESOLVER-SPEC-v0.3.md](spec/RESOLVER-SPEC-v0.3.md) — resolver interface + external resolver protocol
|
|
697
829
|
- [DESIGN-PRINCIPLES.md](DESIGN-PRINCIPLES.md) — architectural decisions and rationale
|
|
698
|
-
- [COMPATIBILITY.md](COMPATIBILITY.md) — backward compatibility guarantees
|
|
830
|
+
- [COMPATIBILITY.md](docs/COMPATIBILITY.md) — backward compatibility guarantees
|
|
699
831
|
|
|
700
832
|
---
|
|
701
833
|
|