Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Mainflux IoT platform is comprised of the following services:

| Service | Description |
|:-----------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------|
| :--------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------- |
| [auth](https://github.com/MainfluxLabs/mainflux/tree/master/auth) | Manages platform's orgs and auth concerns |
| [users](https://github.com/MainfluxLabs/mainflux/tree/master/users) | Manages platform's users and auth concerns |
| [things](https://github.com/MainfluxLabs/mainflux/tree/master/things) | Manages platform's things, profiles, groups and group members |
Expand All @@ -18,6 +18,7 @@ Mainflux IoT platform is comprised of the following services:
| [rules](https://github.com/MainfluxLabs/mainflux/tree/master/rules) | Evaluates threshold rules and Lua scripts against incoming device messages |
| [alarms](https://github.com/MainfluxLabs/mainflux/tree/master/consumers/alarms) | Persists alarms triggered by the rules engine or Lua scripts to PostgreSQL |
| [downlinks](https://github.com/MainfluxLabs/mainflux/tree/master/downlinks) | Manages scheduled outbound HTTP requests (downlinks) for things and groups |
| [shadows](https://github.com/MainfluxLabs/mainflux/tree/master/shadows) | Maintains a persisted desired/reported state record (shadow) for each thing |
| [webhooks](https://github.com/MainfluxLabs/mainflux/tree/master/webhooks) | Forwards device messages to external HTTP endpoints |
| [smtp-notifier](https://github.com/MainfluxLabs/mainflux/tree/master/cmd/smtp-notifier) | Sends email notifications to contacts defined on notifier records |
| [smpp-notifier](https://github.com/MainfluxLabs/mainflux/tree/master/cmd/smpp-notifier) | Sends SMS notifications to contacts defined on notifier records |
Expand Down Expand Up @@ -52,7 +53,6 @@ things and profiles) in CRUD fashion and define access control.
`Thing` represents devices (or applications) connected to Mainflux that uses the
platform for message exchange with other "things".


## Messaging

Mainflux uses [NATS](https://nats.io) as its messaging backbone, due to its
Expand All @@ -65,6 +65,7 @@ However, in order to be post-processed and normalized,
messages should be formatted using [SenML](https://tools.ietf.org/html/draft-ietf-core-senml-08).

## Unified IoT Platform

Running Mainflux on gateway moves computation from cloud towards the edge thus decentralizing IoT system.
Since we can deploy same Mainflux code on gateway and in the cloud there are many benefits but the biggest one is easy deployment and adoption - once the engineers understand how to deploy and maintain the platform, they will have the same known work across the whole edge-fog-cloud continuum.
Same set of tools can be used, same patches and bug fixes can be applied. The whole system is much easier to reason about, and the maintenance is much easier and less costly.
72 changes: 72 additions & 0 deletions docs/shadows.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Shadows

Shadows service maintains a **device shadow** for each thing — a persisted record holding the thing's last _reported_ state and its _desired_ state. It lets users read and set a thing's state even while the thing is offline, and aligns the two whenever the thing reconnects.

A shadow is a single record per thing.

| Field | Description |
| ------------- | ------------------------------------------------------------------------------- |
| `thing_id` | ID of the thing the shadow belongs to |
| `state` | Nested object holding the `desired`, `reported`, and `delta` states (see below) |
| `reported_at` | Unix timestamp (seconds) of the last reported-state update |
| `updated_at` | Unix timestamp (seconds) of the last desired-state update |

## State

`desired`, `reported`, and `delta` are each a free-form JSON object (a set of key/value pairs).

| Field | Description |
| ---------- | -------------------------------------------------------------------------------------------------------- |
| `desired` | State the application wants the thing to reach. |
| `reported` | State the thing last reported. Merged from the thing's telemetry messages. |
| `delta` | Computed subset of `desired` whose values differ from (or are absent in) `reported`. Omitted when empty. |

The `delta` is derived on read and on every state change; it is never stored directly. Keys present only in `reported` are not part of the delta.

## How it works

- **Desired state** is set by a user through the HTTP API. On update, the service recomputes the delta and publishes it to the thing on its command subject (`things.<id>.commands.shadow`).
- **Reported state** is updated automatically as the thing publishes messages. The service consumes messages from the broker, flattens each into a state patch, and merges the patch into `reported` (no-op writes are skipped).
- On each reported-state change, any still-pending delta is re-published, so a reconnecting thing receives commands it missed while offline.

Authorization is delegated to the Things service: reading a shadow requires `viewer` access on the thing's group, while updating or removing a shadow requires `editor` access.

## Managing a shadow

```bash
# Set the desired state for a thing
curl -s -S -i -X PUT \
-H "Authorization: Bearer <user_token>" \
-H "Content-Type: application/json" \
-d '{
"desired": {"fanSpeed": 3, "targetTemp": 21}
}' \
https://localhost/svcshadows/things/<thing_id>/shadows
```

```json
{
"thing_id": "111e4567-e89b-12d3-a456-426614174000",
"state": {
"desired": { "fanSpeed": 3, "targetTemp": 21 },
"reported": { "fanSpeed": 1, "targetTemp": 19 },
"delta": { "fanSpeed": 3, "targetTemp": 21 }
},
"reported_at": 1774342400,
"updated_at": 1774342578
}
```

```bash
# View a thing's shadow
curl -s -S -i \
-H "Authorization: Bearer <user_token>" \
https://localhost/svcshadows/things/<thing_id>/shadows

# Remove a thing's shadow
curl -s -S -i -X DELETE \
-H "Authorization: Bearer <user_token>" \
https://localhost/svcshadows/things/<thing_id>/shadows
```

For the full API reference, see the [API documentation](https://mainfluxlabs.github.io/docs/swagger/).
1 change: 1 addition & 0 deletions docs/swagger/swagger-initializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ window.onload = function() {
{ url: "https://raw.githubusercontent.com/MainfluxLabs/mainflux/refs/heads/master/api/openapi/notifiers.yml", name: "notifiers service" },
{ url: "https://raw.githubusercontent.com/MainfluxLabs/mainflux/refs/heads/master/api/openapi/readers.yml", name: "readers service" },
{ url: "https://raw.githubusercontent.com/MainfluxLabs/mainflux/refs/heads/master/api/openapi/rules.yml", name: "rules service" },
{ url: "https://raw.githubusercontent.com/MainfluxLabs/mainflux/refs/heads/master/api/openapi/shadows.yml", name: "shadows service" },
{ url: "https://raw.githubusercontent.com/MainfluxLabs/mainflux/refs/heads/master/api/openapi/things.yml", name: "things service" },
{ url: "https://raw.githubusercontent.com/MainfluxLabs/mainflux/refs/heads/master/api/openapi/uiconfigs.yml", name: "uiconfigs service" },
{ url: "https://raw.githubusercontent.com/MainfluxLabs/mainflux/refs/heads/master/api/openapi/users.yml", name: "users service" },
Expand Down
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ nav:
- Storage: storage.md
- Rules: rules.md
- Alarms: alarms.md
- Shadows: shadows.md
- Converters: converters.md
- Filestore: filestore.md
- UIConfigs: uiconfigs.md
Expand Down