The edge server provides basic endpoints do retrieve, upload and change device, sensor and actuator data.
You can use REST and MQTT on all endpoints.
- Usage
- Development
- Examples
- create a new device
- change a device name
- delete a device
- list all devices
- create a new sensor or actuator
- change a sensor or actuator name
- list all sensors or actuators
- delete a sensor or actuator
- upload a sensor or actuator value
- upload multiple sensor or actuator values
- get-the-last-sensor-or-actuator-value
- Clouds and Synchronization
- Use MQTT!
- System Settings
- Configuration
This project is part of the Waziup Open Innovation Platform. In most cases you do not want to use this repository without the waziup platform, so have a look the Waziup Gateway at github.com/Waziup/waziup-gateway.
You can compile this project from source with golang and git.
Grab yourself the go language from golang.org and the
git command line tools with apt-get git
or from git-scm.com/download.
Now build the wazigate-edge executable:
git clone https://github.com/Waziup/wazigate-edge.git
cd wazigate-edge
GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -X main.branch=v2 -X main.version=2.3.3 -X main.buildNr=12 -X main.buildtime=156587" -o wazigate .
And run the wazigate-edge server with:
wazigate-edge
If you like to use docker you can use the public waziup docker containers at the Docker Hub. For development you can build this repo on your own using:
git clone https://github.com/Waziup/wazigate-edge.git
cd wazigate-edge
docker build --tag=wazigate-edge .
docker run -p 4000:80 wazigate-edge
... with JavaScript and fetch.
var resp = await fetch(`/device/id`);
var id = await resp.text();
console.log(`device id: ${id}`);
Console output will be like:
device id: 201c85cdbda3
var resp = await fetch("/devices", {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
// id: "5cde6d034b9f61" // let the server choose an id
name: "My Device 1", // readable device name
sensors: [{ // sensors list:
id: "6f840f0b1", // sensor id (hardware id)
name: "My Sensor 1", // readable name
}, {
id: "df34b9f612",
name: "My Sensor 2",
}],
actuators: [{ // actuators list:
id: "40f034",
name: "My Actuator 1",
}],
})
});
// the device id will be returned
var deviceId = await resp.json();
alert(`new device.id: ${deviceId}`);
Console output will be like:
new device.id: 5cde6d034b9f610ff8373bdb
var deviceId = "5cde6d034b9f610ff8373bdb";
await fetch(`/devices/${deviceId}/name`, {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify("New Device Name")
});
var deviceId = "5cde6d034b9f610ff8373bdb";
fetch(`/devices/${deviceId}`, {
method: "DELETE",
});
var resp = await fetch("/devices");
var devices = await resp.json();
console.log(devices);
Console output will be like: (without comments)
[{
name: "My Device 1",
id: "5cde6d034b9f61",
// Sensors List
sensors: [{
// unique sensor id
id: "6f840f0b1",
// Sensor name
name: "My Sensor 1",
// time when last modified
modified: "2019-06-03T12:31:34.331Z",
// time when created
created: "2019-06-03T12:31:34.331Z",
// time last value received
time: "2019-06-03T12:15:47.971Z",
// last value
value: null
},{
id: "df34b9f612",
name: "My Sensor 2",
modified: "0001-01-01T00:00:00Z",
created: "2019-06-03T12:31:34.331Z",
time: "2019-06-03T12:15:47.971Z",
value: null
}],
// Actuators List
actuators: [{
id: "40f034",
name: "My Actuator 1",
modified: "2019-06-03T12:30:52.106Z",
created: "2019-06-03T12:31:34.331Z",
time: "2019-06-03T12:15:47.971Z",
value: null
}],
modified: "2019-06-03T12:30:52.106Z",
created: "2019-06-03T12:31:34.331Z"
}]
- Modified-times for devices get updated when the device name changes (using POST .../name) but not if a new sensor or actuator gets added or deleted.
- Modified-times on sensors or actuators get updated when the sensor or actuator name changes, but not if a new value gets posted.
- Time and Value for each sensor are the same as at GET .../value
var deviceId = "5cde6d034b9f610ff8373bdb";
await fetch(`/devices/${deviceId}/sensors`, {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
id: "0ff8373bd", // sensor id (hardware id)
name: "My Sensor 3", // readable name
})
});
The same goes for actuators. Just replace sensors
with actuators
.
var sensorId = "0ff8373bd";
var deviceId = "5cde6d034b9f610ff8373bdb";
await fetch(`/devices/${deviceId}/sensors/${sensorId}/name`, {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify("New Sensor Name")
});
var deviceId = "5cde6c194b9f610ff8373bda";
var resp = await fetch(`/devices/${deviceId}/sensors`);
var sensors = await resp.json();
console.log(sensors);
var sensorId = "0ff8373bd";
var deviceId = "5cde6d034b9f610ff8373bdb";
fetch(`/devices/${deviceId}/sensors/${sensorId}`, {
method: "DELETE",
});
var sensorId = "0ff8373bd";
var deviceId = "5cde6d034b9f610ff8373bdb";
var value = 42; // numeric value
// or
var value = "Temp45%23"; // string value
// or
var value = {lat: 52, long: 7}; // complex value
// or
var value = {
time: new Date(), // value at specific time
value: 42 // value
};
fetch(`/devices/${deviceId}/sensors/${sensorId}/value`, {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(value)
});
var sensorId = "0ff8373bd";
var deviceId = "5cde6d034b9f610ff8373bdb";
var values = [42, 45, 47]; // values array
// or
var values = ["a", 0x0b, "cde"]; // ...
// or
var values = [
{ // values with timestamp
time: new Date(),
value: 42,
}, {
time: new Date(),
value: 43,
}
]
fetch(`/devices/${deviceId}/sensors/${sensorId}/values`, {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(values)
});
var sensorId = "0ff8373bd";
var deviceId = "5cde6d034b9f610ff8373bdb";
var resp = await fetch(`/devices/${deviceId}/sensors/${sensorId}/value`);
var value = await resp.json();
console.log(value);
var sensorId = "0ff8373bd";
var deviceId = "5cde6d034b9f610ff8373bdb";
var resp = await fetch(`/devices/${deviceId}/sensors/${sensorId}/values`);
var values = await resp.json();
console.log(values);
fetch(`/clouds`, {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
rest: "api.waziup.io/api/v2",
mqtt: "api.waziup.io",
paused: true, // default false
credentials: {
username: "myUsername",
token: "myPassword"
}
})
});
// the cloud id will be returned
var cloudId = await resp.json();
alert(`new cloud.id: ${cloudId}`);
Console output will be like:
new cloud.id: 5ce2793d4b9f612a04a7951d
var resp = await fetch("/clouds");
var clouds = await resp.json();
console.log(clouds);
Output will be like:
{
"5ce2793d4b9f612a04a7951d": {
id: "5ce2793d4b9f612a04a7951d",
paused: true,
rest: "api.waziup.io/api/v2",
mqtt: "api.waziup.io",
credentials: {
username: "myUsername",
token: "myPassword"
},
// bytes in queue waiting for sync with server
queue: 136,
// sync status code (200 = OK)
statusCode: 200,
// readable status text or error, if any
statusText: "MQTT connected for persistent sync."
}
}
statusCode can be one of:
200
OK. The synchronization is active.
0
The synchronization is paused.
Any other code: There was a problem with this synchronization.
var cloudId = "5ce2793d4b9f612a04a7951d";
fetch(`/clouds/${cloudId}/paused`, {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(false) // or true
});
var cloudId = "5ce2793d4b9f612a04a7951d";
fetch(`/clouds/${cloudId}/credentials`, {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: "myNewUserName",
token: "myNewPassword",
})
});
var cloudId = "5ce2793d4b9f612a04a7951d";
fetch(`/clouds/${cloudId}/mqtt`, {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify("waziup.myserver.com")
});
var cloudId = "5ce2793d4b9f612a04a7951d";
fetch(`/clouds/${cloudId}/rest`, {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify("waziup.myserver.com")
});
With MQTT you can publish values for the sensor, which is more efficient than the REST interface. You will need a MQTT client like Eclipse Mosquitto (commandline) or HiveMQ MQTT Websocket Client. For the following examples we will use the HiveMQ Client.
Subscriptions are especially usefull if you want to listen for changes and want to get notified when new sensor values arrive. They will be triggered by both Publishes (via MQTT) and Post (via REST).
Connect to your Waziup Gateway using the connection settings:
- Host: Gateway IP
- Port: 80 (for in-browser MQTT via Websocket) or default 1883
- Client: (any)
- MQTT Version: 3.1.1 (MQTT) or 3.1.0 (MQIsdp)
You can now publish and subscribe topics like sensor-values or actuator-values.
To make a new subscription, click "Add New Topic Subscription" and enter a valid
topic, like the values-topic from an existing sensor. If you have completed the previous examples, you could use devices/5cd92df34b9f6126f840f0b1/sensors/6f840f0b1/value
.
Remember that messages must be valid JSON, so enquote strings like "my string"
.
See http://www.hivemq.com/demos/websocket-client/.
Equivalent mosquitto calls look like:
# Publish Values:
mosquitto_pub \
-t "devices/5cd92df34b9f6126f840f0b1/sensors/df34b9f612/value" \
-m 456
# Subscribe to topics:
mosquitto_sub \
-t "devices/5cd92df34b9f6126f840f0b1/sensors/df34b9f612/value" \
# Subscribe to all sensors of one device:
mosquitto_sub \
-t "devices/5cd92df34b9f6126f840f0b1/sensors/*/value" \
# Subscribe to actuating-data of all devices:
mosquitto_sub \
-t "devices/*/actuator/*/value" \
# Subscribe to all changes on one device:
mosquitto_sub \
-t "devices/5cd92df34b9f6126f840f0b1/#" \
# Subscribe to literally everything on devices:
mosquitto_sub \
-t "devices/#" \
Mosquitto is available for both Linux and Windows.
There are a few things to keep in mind when using MQTT:
- Use port 80 when using MQTT via REST in your browser and port 1883 otherwise. Most clients will have these ports already configured.
- Topics are equivalent to URLs from the REST API. You can use any url as topic and vice versa.
- Subscriptions will be triggered by both Publishes (via MQTT) and Post (via REST).
- Topics do not start with a slash '/'.
- Use only valid JSON objects as payload! (Don't forget to enquote strings!)
The following APIs are for system settings and debugging.
var resp = await fetch("/sys/uptime");
var uptime = await resp.text();
console.log(uptime);
Console output will be like 6m29.5201577s
.
Attention! This call will clear the local database, removing all devices and all data values.
This can not be undone!
var resp = await fetch("/sys/clear_all", {method: "PUT"});
console.log(resp.ok);
For every session, the wazigate-edge will create a log file at ./logs
that equals the cmd output (your console output).
var resp = await fetch("/sys/logs");
var logs = await resp.json();
console.log(logs);
Console output will be like:
[
{name: "5cff90374b9f6139d44193e6.txt", time: "2019-06-11T13:27:51+02:00", size: 2187},
{name: "5cff92874b9f6136541f4aaa.txt", time: "2019-06-11T13:37:43+02:00", size: 523},
...
]
The last file in this list will be the current log file. This file can not be deleted.
var file = "5cff92874b9f6136541f4aaa.txt";
var resp = await fetch("/sys/log/"+file);
var log = await resp.text();
console.log(log);
The file is text only and will look like:
[WWW ] Serving from "/var/www"
[DB ] Dialing MongoDB at "localhost:27017"...
[ ] Local device id is "309c23cdbda6".
[CLOUD] 1 clouds from config:
[CLOUD] "5cebcfa04b9f6119688b3cdc" "//api.waziup.io/api/v2" (pause:false)
[UP ] Dialing REST "https://api.waziup.io/api/v2"...
[MQTT ] MQTT Server at ":1883".
[HTTP ] HTTP Server at ":80". Use "http://".
[WS ] MQTT via WebSocket Server at":80". Use "ws://".
[UP ] Authentication successfull.
[MQTT ] Connect "mosqsub|12576-DESKTOP-L" <nil>
[MQTT ] Subscribe "mosqsub|12576-DESKTOP-L" "sys/log" QoS:0
[UP ] Device "5cde6d034b9f61" found. Checking for updates.
[UP ] Dialing MQTT "api.waziup.io:1883"...
[HTTP ] [::1]:62660 200 GET "/sys/logs" s:0
[HTTP ] [::1]:62660 200 GET "/sys/log/5cff90374b9f6139d44193e6.txt" s:0
You can subscribe to the system log topic to monitor the log in real-time!
mosquitto_sub -t "sys/log" -V "mqttv311"
With HiveMQ use port 80, click connect and subscribe to sys/log.
The first result will always be [MQTT ] Subscribe "..." "sys/log" QoS:0
which is the log generated from the mqtt subscription you just made.
var file = "5cff92874b9f6136541f4aaa.txt";
fetch("/sys/log/"+file, {
method: "DELETE",
});
The application is ready to use with no configration needed!
You might want to change some variables if you
- run multiple wazigate-edge applications on the same machine (maybe for testing) or if you
- use wazigate-edge inside a docker-container.
Env Variables
WAZIUP_HTTP_ADDR = :80 HTTP Listen Address
WAZIUP_HTTPS_ADDR = :443 HTTPS Listen Address
WAZIUP_MQTT_ADDR = :1883 MQTT Listen Address
WAZIUP_MQTTS_ADDR = :8883 MQTTS Listen Address
WAZIUP_TLS_CRT = TLS Cert File (.crt)
WAZIUP_TLS_KEY = TLS Key File (.key)
WAZIUP_MONGO = localhost:27017 MongoDB Address
WAZIUP_CLOUDS_FILE = clouds.json Clouds Config File
WAZIUP_LOG = date,time,verbose Log Settings, see below
Note that MQTT via Websocket is available together with the REST API on HTTP and HTTPS. To disable serving static files of www, use -www "" (an empty string).
Commandline Arguments
-crt TLS Cert File (.crt)
-key TLS Key File (.key)
-www HTTP files root, default "/var/www"
-db MongoDB address, default "localhost:27017"
Commandline arguments override env variables! Secure connections will only be used if -crt and -key are present.
Config Files
clouds.json Saves /clouds setttings
Logging Files
All files at log/*.txt
are log files generated with each session.
Une can use the WAZIUP_LOG
env variable to control what is logged.
To log date and time, use date
and time
. For more or less logging use one of error
, warn
, normal
, verbose
, debug
.
The default log settings are: WAZIUP_LOG = normal
(with no date and time).