Skip to content

Commit ebf3279

Browse files
committed
mqtt support
1 parent 9c75aae commit ebf3279

File tree

6 files changed

+118
-29
lines changed

6 files changed

+118
-29
lines changed

README.md

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,38 @@ IO_FEED=feed
2929
IO_KEY=...
3030
```
3131

32-
## createData (REST)
32+
This extension uses the following settings:
3333

34-
The createData function will upload a value to the Adafruit.io feed using the REST APIs
35-
and return the HTTP status code.
34+
- IO_KEY: (required) access key
35+
- IO_FEED: feed name
36+
- IO_USER: io.adafruit.com user name
37+
- IO_LAT: (optional) latitude (as a number)
38+
- IO_LON: (optional) longitude (as a number)
39+
- IO_ELE: (optional) elevation (as a number)
40+
41+
## REST
42+
43+
The createData function will upload a value to the Adafruit.io feed using the [REST APIs](https://io.adafruit.com/api/docs/#create-data) and return the HTTP status code.
3644

3745
```ts
3846
import { createData } from "devicescript-adafruit-io"
3947
const value = await temperature.reading.read()
4048
const status = await createData(value)
4149
console.log({ status })
4250
```
51+
52+
## MQTT
53+
54+
This API connects to the [MQTT](https://io.adafruit.com/api/docs/mqtt.html#adafruit-io-mqtt-api)
55+
broker and let's you publish sensor data through the feed topics.
56+
57+
```ts
58+
import {
59+
publishData,
60+
startAdafruitIOMQTTClient,
61+
} from "devicescript-adafruit-io"
62+
63+
const client = await startAdafruitIOMQTTClient()
64+
65+
await publishData(client, 456)
66+
```

src/http.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
import { fetch } from "@devicescript/net"
2-
import { FeedOptions, loadOptions } from "./options"
2+
import {
3+
FeedOptions,
4+
UserOptions,
5+
loadFeedOptions,
6+
loadUserOptions,
7+
} from "./options"
38

49
/**
510
* Creates a data point in a Adafruit.io feed using
611
* the {@link https://io.adafruit.com/api/docs/#create-data | REST API}
712
*
8-
* This extension uses the following settings:
9-
*
10-
* - IO_KEY: (required) access key
11-
* - IO_FEED: feed name
12-
* - IO_USER: io.adafruit.com user name
13-
* - IO_LAT: (optional) latitude (as a number)
14-
* - IO_LON: (optional) longitude (as a number)
15-
* - IO_ELE: (optional) elevation (as a number)
16-
*
1713
* @param value numerical value to upload
18-
* @param options optional latitude longitude
14+
* @param options optional settings
1915
* @returns HTTP status code
2016
*/
21-
export async function createData(value: number, options?: FeedOptions) {
22-
const { key, feed, user, lat, lon, ele } = await loadOptions(options)
17+
export async function createData(
18+
value: number,
19+
options?: UserOptions & FeedOptions
20+
) {
21+
const { key, user } = await loadUserOptions(options)
22+
const { feed, lat, lon, ele } = await loadFeedOptions(options)
2323

2424
const url = `https://io.adafruit.com/api/v2/${user}/feeds/${feed}/data`
2525
const headers = { "X-AIO-Key": key, "Content-Type": "application/json" }

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from "./options"
22
export * from "./http"
3+
export * from "./mqtt"

src/main.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1-
import { createData } from "."
1+
import { createData, publishData, startAdafruitIOMQTTClient } from "."
22

33
await createData(123)
4+
5+
const client = await startAdafruitIOMQTTClient()
6+
7+
await publishData(client, 456)

src/mqtt.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { MQTTClient, startMQTTClient } from "@devicescript/net"
2+
import {
3+
FeedOptions,
4+
UserOptions,
5+
loadFeedOptions,
6+
loadUserOptions,
7+
} from "./options"
8+
9+
/**
10+
* Starts a MQTT client for the Adafruit.io broker
11+
* @see {@link https://io.adafruit.com/api/docs/mqtt.html#adafruit-io-mqtt-api}
12+
*/
13+
export async function startAdafruitIOMQTTClient(options?: UserOptions) {
14+
const { user, key } = await loadUserOptions(options)
15+
const client = await startMQTTClient({
16+
username: user,
17+
password: key,
18+
host: "io.adafruit.com",
19+
port: 8883,
20+
})
21+
;(client as any).__user = user
22+
return client
23+
}
24+
25+
/**
26+
* Publishes a data entry on the given feed
27+
* @see {@link https://io.adafruit.com/api/docs/mqtt.html#adafruit-io-mqtt-api}
28+
* @param client MQTT client opened with startAdafruitIOMQTTClient
29+
*/
30+
export async function publishData(
31+
client: MQTTClient,
32+
value: number | Record<string, number>,
33+
options?: FeedOptions
34+
) {
35+
const { feed, lon, lat, ele } = await loadFeedOptions(options)
36+
const user = (client as any).__user as string
37+
const topic = `${user}/f/${feed}/json`
38+
const payload: any = { value }
39+
if (lon !== undefined) payload.lon = lon
40+
if (lat !== undefined) payload.lat = lat
41+
if (ele !== undefined) payload.ele = ele
42+
await client.publish(topic, payload)
43+
}

src/options.ts

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,55 @@
11
import { readSetting } from "@devicescript/settings"
22

3+
/**
4+
* Adafruit.io configuration options
5+
*/
6+
export interface UserOptions {
7+
user?: string
8+
}
9+
10+
/**
11+
* Merges the passed options and the options in the settings
12+
* - IO_KEY: (required) access key
13+
* - IO_USER: io.adafruit.com user name
14+
* @param options
15+
* @returns a valid option object, including the key
16+
* @throws Error missing user or feed information
17+
*/
18+
export async function loadUserOptions(
19+
options?: UserOptions
20+
): Promise<UserOptions & { key: string }> {
21+
const key = await readSetting("IO_KEY")
22+
if (!key) throw new Error("Adafruit.io: missing secret IO_KEY")
23+
let { user } = options || {}
24+
user = user || (await readSetting("IO_USER"))
25+
if (!user) throw new Error("Adafruit.io: missing setting IO_USER")
26+
return { user, key }
27+
}
28+
329
/**
430
* Adafruit.io configuration options
531
*/
632
export interface FeedOptions {
733
feed?: string
8-
user?: string
934
lat?: number
1035
lon?: number
1136
ele?: number
1237
}
1338

1439
/**
1540
* Merges the passed options and the options in the settings
16-
* - IO_KEY: (required) access key
1741
* - IO_FEED: feed name
18-
* - IO_USER: io.adafruit.com user name
1942
* - IO_LAT: (optional) latitude (as a number)
2043
* - IO_LON: (optional) longitude (as a number)
2144
* - IO_ELE: (optional) elevation (as a number)
2245
* @param options
2346
* @returns a valid option object, including the key
2447
* @throws Error missing user or feed information
2548
*/
26-
export async function loadOptions(
49+
export async function loadFeedOptions(
2750
options?: FeedOptions
28-
): Promise<FeedOptions & { key: string }> {
29-
const key = await readSetting("IO_KEY")
30-
if (!key) throw new Error("Adafruit.io: missing secret IO_KEY")
31-
let { feed, user, lat, lon, ele } = options || {}
32-
user = user || (await readSetting("IO_USER"))
33-
if (!user) throw new Error("Adafruit.io: missing setting IO_USER")
51+
): Promise<FeedOptions> {
52+
let { feed, lat, lon, ele } = options || {}
3453
feed = feed || (await readSetting("IO_FEED"))
3554
if (!feed) throw new Error("Adafruit.io: missing setting IO_FEED")
3655

@@ -39,9 +58,7 @@ export async function loadOptions(
3958
ele = ele || (await readSetting<number>("IO_ELE"))
4059

4160
return {
42-
key,
4361
feed,
44-
user,
4562
lat,
4663
lon,
4764
ele,

0 commit comments

Comments
 (0)