Module github.com/infinimesh/addons. Connectors that sit beside core. They are not part of the platform process.
Apache-2.0.
| Addon | What it does |
|---|---|
timeseries |
API to RedisTimeSeries, with Grafana |
kafka |
API to a Kafka or KafScale topic, JSON keyed by device id |
ota-hawkbit |
hawkBit Management API for namespace OTA |
ota-mender |
Mender open source Management API for namespace OTA |
ota-webhook |
Signed HTTP posts for namespace OTA |
webhook |
API to an HTTP endpoint, one signed JSON POST per shadow update |
postgres |
API to a Postgres table, optionally a TimescaleDB hypertable |
influxdb |
API to InfluxDB 2, InfluxDB Cloud or InfluxDB 3, one point per shadow update |
mqttbridge |
API to an existing MQTT broker, JSON per shadow update on a topic template |
cloudconnect |
API to CSV files, then S3, Google Cloud Storage or Azure Blob |
redisstream |
API to the Redis stream objects, read by the sinks below |
elasticsearch |
Redis stream to the Elasticsearch index infinimesh |
snowflake |
Redis stream to the Snowflake table infinimesh.device_states |
saphana |
Redis stream to the SAP HANA table devices |
sdk holds the shared API client, the device worker manager, the shadow runner, the JSON message and the batcher used by the shadow addons, and the Redis stream consumer.
To write your own addon, see docs/write-an-addon.md.
From this repository, with API_URL pointing at a running platform:
docker compose -f timeseries/docker-compose.yml up --buildThe sink compose files (elasticsearch, snowflake, saphana) already start redisstream, so you do not run it on its own as well.
Each compose file's build context is the repository root. Set USERNAME, PASSWORD, and API_URL in that file. Placeholders are CHANGEME and https://api.example.com.
The SDK uses the core v3 gRPC API through the generated clients in infinimesh/proto, the same way inf does.
USERNAMEandPASSWORDare a standard infinimesh account. A fresh core install has the root accountinfinimeshwith the password fromINF_DEFAULT_ROOT_PASS. A separate read only account is better for addons. Creating a plugin, including an OTA plugin, needs a root token fromPOST /v1/token. See Write an addon.ota-hawkbit,ota-mender, andota-webhookdo not useUSERNAMEorPASSWORD. They sendOTA_ADDON_TOKEN, the bearer frominf plugins create. All three are released in addons v3.4.2 as source, with no published images. The webhook addon needs core 3.4.2 or newer.API_URLis the gRPC address.https://api.example.comuses TLS on port 443, which the core compose setup routes to the api service.http://api.example.com:8000uses plain gRPC on thegrpcentry point, orhttp://api:8000from inside the core compose network. With no scheme, TLS is used.- Addons see every device the account can see. For each device they ask core for a short device token with read access and stream its shadow.
webhook,postgres,kafka, andmqttbridgealso send the desired and connection state unless their*_ONLY_REPORTEDsetting istrue.influxdbadds the desired state withINFLUX_INCLUDE_DESIRED=true.timeseries,redisstream, and Cloud Connect use only the reported state. The v3 shadow has no version, so theversionfield the sinks store is empty.
SNOWFLAKE_INITDB=true creates the Snowflake database and table. Cloud Connect commands are cloudconnect/csvwriter, s3, cloudstorage, and blob.
make commit-check runs fmt, race, test-fuzz, and code-ql-gate. fmt writes Go files that gofmt would change. code-ql runs the CodeQL CLI and writes SARIF under .tmp/codeql/. The gate fails when a result is level error, ignoring paths under vendor. jq is required. GitHub Actions runs the same race and fuzz steps, and CodeQL on pull requests.
go test ./...
go build -o redisstream ./redisstream