├── hivemq-mqtt-web-client
└── config.js
├── ruuvitag-demo-diagram.png
├── ruuvitag-demo-grafana.png
├── ruuvitag-demo-node-red.png
├── mosquitto
└── config
│ └── mosquitto.conf
├── .gitignore
├── grafana
├── provisioning
│ ├── dashboards
│ │ └── local.yml
│ └── datasources
│ │ └── influxdb.yml
└── dashboards
│ └── ruuvitag.json
├── bt-mqtt-gateway
└── config.yaml
├── LICENSE
├── docker-compose.yml
├── docker-compose-epaper.yml
├── README.md
├── ruuvitag-demo-diagram.dot
├── telegraf
└── telegraf.conf
└── node-red
├── settings.js
└── flows.json
/hivemq-mqtt-web-client/config.js:
--------------------------------------------------------------------------------
1 | websocketserver = 'localhost';
2 | websocketport = 9001;
3 |
--------------------------------------------------------------------------------
/ruuvitag-demo-diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/koenvervloesem/ruuvitag-demo/HEAD/ruuvitag-demo-diagram.png
--------------------------------------------------------------------------------
/ruuvitag-demo-grafana.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/koenvervloesem/ruuvitag-demo/HEAD/ruuvitag-demo-grafana.png
--------------------------------------------------------------------------------
/ruuvitag-demo-node-red.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/koenvervloesem/ruuvitag-demo/HEAD/ruuvitag-demo-node-red.png
--------------------------------------------------------------------------------
/mosquitto/config/mosquitto.conf:
--------------------------------------------------------------------------------
1 | port 1883
2 | listener 9001
3 | protocol websockets
4 | persistence true
5 | persistence_location /mosquitto/data/
6 | log_dest file /mosquitto/log/mosquitto.log
7 | allow_anonymous true
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | grafana/var/grafana.db
2 | grafana/var/plugins
3 | grafana/var/png
4 | influxdb/
5 | node-red/.config.json
6 | node-red/.config.json.backup
7 | node-red/.flows.json.backup
8 | node-red/.sessions.json
9 | node-red/flows_cred.json
10 | node-red/package.json
11 | node-red/settings.js
12 |
--------------------------------------------------------------------------------
/grafana/provisioning/dashboards/local.yml:
--------------------------------------------------------------------------------
1 | apiVersion: 1
2 |
3 | providers:
4 | - name: 'default'
5 | orgId: 1
6 | folder: ''
7 | type: file
8 | disableDeletion: false
9 | updateIntervalSeconds: 10 # How often Grafana scans for changed dashboards
10 | options:
11 | path: /var/lib/grafana/dashboards
12 |
--------------------------------------------------------------------------------
/grafana/provisioning/datasources/influxdb.yml:
--------------------------------------------------------------------------------
1 | apiVersion: 1
2 |
3 | datasources:
4 | - name: "InfluxDB"
5 | orgId: 1
6 | id: 1
7 | type: "influxdb"
8 | access: "proxy"
9 | typeLogoUrl: "public/app/plugins/datasource/influxdb/img/influxdb_logo.svg"
10 | url: "http://influxdb:8086"
11 | password: ""
12 | user: ""
13 | database: "telegraf"
14 | basicAuth: false
15 | isDefault: true
16 | readOnly: false
17 |
--------------------------------------------------------------------------------
/bt-mqtt-gateway/config.yaml:
--------------------------------------------------------------------------------
1 | mqtt:
2 | host: localhost
3 | port: 1883
4 | topic_prefix: bt-mqtt-gateway
5 | client_id: bt-mqtt-gateway
6 | availability_topic: availability
7 |
8 | manager:
9 | command_timeout: 30
10 | workers:
11 | ruuvitag:
12 | args:
13 | devices:
14 | tag1: F9:DA:D2:0D:62:24
15 | tag2: C8:03:24:74:7E:0E
16 | tag3: C5:98:17:63:C3:E3
17 | tag4: D8:58:5E:B8:ED:DF
18 | topic_prefix: ruuvitag
19 | update_interval: 1
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Koen Vervloesem
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.7'
2 |
3 | services:
4 | mosquitto:
5 | image: eclipse-mosquitto
6 | container_name: mosquitto
7 | restart: always
8 | volumes:
9 | - ./mosquitto:/mosquitto
10 | ports:
11 | - "1883:1883"
12 | - "9001:9001"
13 | hivemq-mqtt-web-client:
14 | image: koenvervloesem/hivemq-mqtt-web-client
15 | container_name: hivemq-mqtt-web-client
16 | restart: always
17 | volumes:
18 | - ./hivemq-mqtt-web-client/config.js:/var/www/html/config.js
19 | ports:
20 | - "8080:80"
21 | depends_on:
22 | - mosquitto
23 | bt-mqtt-gateway:
24 | image: zewelor/bt-mqtt-gateway
25 | container_name: bt-mqtt-gateway
26 | restart: always
27 | volumes:
28 | - ./bt-mqtt-gateway/config.yaml:/config.yaml
29 | # These capabilities are needed for Bluetooth
30 | cap_add:
31 | - NET_ADMIN
32 | - SYS_ADMIN
33 | - SYS_RESOURCE
34 | # The Docker host should have working Bluetooth
35 | network_mode: host
36 | depends_on:
37 | - mosquitto
38 | node-red:
39 | image: nodered/node-red
40 | container_name: node-red
41 | restart: always
42 | volumes:
43 | - ./node-red:/data
44 | ports:
45 | - "1880:1880"
46 | environment:
47 | - TZ=Europe/Brussels
48 | # Install node-red-dashboard before starting Node-RED
49 | entrypoint: /bin/bash
50 | command: ["-c", "npm install node-red-dashboard && npm start -- --userDir /data"]
51 | depends_on:
52 | - mosquitto
53 | telegraf:
54 | image: telegraf
55 | container_name: telegraf
56 | restart: always
57 | volumes:
58 | - ./telegraf:/etc/telegraf
59 | depends_on:
60 | - influxdb
61 | - mosquitto
62 | influxdb:
63 | image: influxdb
64 | container_name: influxdb
65 | restart: always
66 | volumes:
67 | - ./influxdb/var:/var/lib/influxdb
68 | ports:
69 | - "8086:8086"
70 | grafana:
71 | # Use :master until Grafana 6.5 is released because it has a fix for ARM
72 | # See https://github.com/grafana/grafana/issues/19585
73 | image: grafana/grafana:master
74 | container_name: grafana
75 | restart: always
76 | volumes:
77 | - ./grafana/dashboards:/var/lib/grafana/dashboards
78 | - ./grafana/provisioning:/etc/grafana/provisioning
79 | ports:
80 | - "3000:3000"
81 | user: "472"
82 | depends_on:
83 | - influxdb
84 |
--------------------------------------------------------------------------------
/docker-compose-epaper.yml:
--------------------------------------------------------------------------------
1 | version: '3.7'
2 |
3 | services:
4 | mosquitto:
5 | image: eclipse-mosquitto
6 | container_name: mosquitto
7 | restart: always
8 | volumes:
9 | - ./mosquitto:/mosquitto
10 | ports:
11 | - "1883:1883"
12 | - "9001:9001"
13 | hivemq-mqtt-web-client:
14 | image: koenvervloesem/hivemq-mqtt-web-client
15 | container_name: hivemq-mqtt-web-client
16 | restart: always
17 | volumes:
18 | - ./hivemq-mqtt-web-client/config.js:/var/www/html/config.js
19 | ports:
20 | - "8080:80"
21 | depends_on:
22 | - mosquitto
23 | bt-mqtt-gateway:
24 | image: zewelor/bt-mqtt-gateway
25 | container_name: bt-mqtt-gateway
26 | restart: always
27 | volumes:
28 | - ./bt-mqtt-gateway:/config
29 | # These capabilities are needed for Bluetooth
30 | cap_add:
31 | - NET_ADMIN
32 | - SYS_ADMIN
33 | # The Docker host should have working Bluetooth
34 | network_mode: host
35 | depends_on:
36 | - mosquitto
37 | ruuvitag-epaper:
38 | image: ruuvitag-epaper
39 | container_name: ruuvitag-epaper
40 | restart: always
41 | # Needed for proper timezone handling
42 | volumes:
43 | - /etc/localtime:/etc/localtime
44 | network_mode: host
45 | depends_on:
46 | - mosquitto
47 | # Should be privileged to get GPIO and SPI access
48 | privileged: true
49 | node-red:
50 | image: nodered/node-red
51 | container_name: node-red
52 | restart: always
53 | volumes:
54 | - ./node-red:/data
55 | ports:
56 | - "1880:1880"
57 | environment:
58 | - TZ=Europe/Brussels
59 | # Install node-red-dashboard before starting Node-RED
60 | entrypoint: /bin/bash
61 | command: ["-c", "npm install node-red-dashboard && npm start -- --userDir /data"]
62 | depends_on:
63 | - mosquitto
64 | telegraf:
65 | image: telegraf
66 | container_name: telegraf
67 | restart: always
68 | volumes:
69 | - ./telegraf:/etc/telegraf
70 | depends_on:
71 | - influxdb
72 | - mosquitto
73 | influxdb:
74 | image: influxdb
75 | container_name: influxdb
76 | restart: always
77 | volumes:
78 | - ./influxdb/var:/var/lib/influxdb
79 | ports:
80 | - "8086:8086"
81 | grafana:
82 | # Use :master until Grafana 6.5 is released because it has a fix for ARM
83 | # See https://github.com/grafana/grafana/issues/19585
84 | image: grafana/grafana:master
85 | container_name: grafana
86 | restart: always
87 | volumes:
88 | - ./grafana/dashboards:/var/lib/grafana/dashboards
89 | - ./grafana/provisioning:/etc/grafana/provisioning
90 | ports:
91 | - "3000:3000"
92 | user: "472"
93 | depends_on:
94 | - influxdb
95 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RuuviTag Demo
2 |
3 | This is a demo of reading Bluetooth Low Energy sensor measurements of RuuviTag environmental sensors and feeding them to MQTT, a database and dashboards.
4 |
5 | This project is not affiliated to the [Ruuvi](https://ruuvi.com/) company in any way.
6 |
7 | ## Screenshots
8 |
9 | Grafana dashboard:
10 |
11 | 
12 |
13 | Node-RED dashboard:
14 |
15 | 
16 |
17 | ## System requirements
18 | You need a Linux system with Bluetooth Low Energy (BLE) adapter, so at least Bluetooth 4.0.
19 |
20 | The demo uses Docker, so it has to be installed.
21 |
22 | This demo has been tested on:
23 |
24 | * Raspbian Buster Lite (on a Raspberry Pi 3B)
25 | * Ubuntu Desktop 19.10
26 |
27 | All instructions assume the first configuration. It should run on other Linux systems with minor adjustments, though.
28 |
29 | ### Checking your Bluetooth adapter
30 | Your system should have a Bluetooth Low Energy adapter, as is available in all recent Raspberry Pi models. You can verify this with:
31 |
32 | ```shell
33 | hciconfig -a
34 | ```
35 |
36 | This should show a device **hci0** as **UP RUNNING** and the **LMP Version** should be at least 4.0.
37 |
38 | ### Installing Docker and Docker Compose
39 | Docker can be installed with:
40 |
41 | ```shel
42 | curl -sSL https://get.docker.com | sh
43 | ```
44 |
45 | And give the `pi` user access to Docker by adding it to the `docker` group:
46 |
47 | ```shell
48 | sudo usermod pi -aG docker
49 | ```
50 |
51 | Log out and then log in again, so the group permissions are applied to your session.
52 |
53 | Then install Python's pip package manager:
54 |
55 | ```shell
56 | sudo apt install python3-pip
57 | ```
58 |
59 | And install Docker Compose:
60 |
61 | ```shell
62 | sudo pip3 install docker-compose
63 | ```
64 |
65 | ## Installation
66 | Clone the repository (you may have to `sudo apt install git` first) and enter the directory:
67 |
68 | ```shell
69 | git clone https://github.com/koenvervloesem/ruuvitag-demo.git
70 | cd ruuvitag-demo
71 | ```
72 |
73 | Change the owner of the `grafana` directory:
74 |
75 | ```shell
76 | sudo chown -R 472:472 grafana
77 | ```
78 |
79 | ## Configuration
80 | Add the MAC addresses of your RuuviTag sensors to the `bt-mqtt-gateway/config.yaml` file. You can find these by scanning for Bluetooth Low Energy devices in your neighborhood:
81 |
82 | ```shell
83 | sudo hcitool lescan
84 | ```
85 |
86 | Or you can run the Ruuvi Station app [on Android](https://github.com/ruuvi/com.ruuvi.station) or [on iOS](https://github.com/ruuvi/com.ruuvi.station.ios) and have a look at the MAC address in the tag settings of each RuuviTag.
87 |
88 | The Node-RED flow and Grafana dashboard suppose that you have four tags, called `tag1`, `tag2`, `tag3` and `tag4`. So I suggest that initially you leave these names in `bt-mqtt-gateway/config.yaml`. After starting up the demo, you can always change the configuration.
89 |
90 | ## Starting the demo
91 | Starting the demo is easy, as it's using Docker Compose:
92 |
93 | ```shell
94 | docker-compose up -d
95 | ```
96 |
97 | This starts seven Docker containers:
98 |
99 | * [bt-mqtt-gateway](https://github.com/zewelor/bt-mqtt-gateway): Reads RuuviTag sensor measurements using Bluetooth Low Energy and forwards them to a MQTT broker.
100 | * [Mosquitto](https://mosquitto.org/): Receives the MQTT messages from bt-mqtt-gateway and relays them to anyone who is interested.
101 | * [HiveMQ MQTT Web Client](https://github.com/hivemq/hivemq-mqtt-web-client): Connects to Mosquitto and shows you the MQTT messages in your web browser using WebSockets.
102 | * [Node-RED](https://nodered.org/): Subscribes to the MQTT messages from Mosquitto and shows the values in a dashboard.
103 | * [Telegraf](https://www.influxdata.com/time-series-platform/telegraf/): Collects MQTT messages from Mosquitto and sends the values to InfluxDB.
104 | * [InfluxDB](https://www.influxdata.com/): Stores all the values of the RuuviTag measurements in a time-series database.
105 | * [Grafana](https://grafana.com/): Shows the values of the InfluxDB database in a dashboard.
106 |
107 | You have access to:
108 |
109 | * The MQTT web client on http://localhost:8080
110 | * The Node-RED flow on http://localhost:1880
111 | * The Node-RED dashboard on http://localhost:1880/ui
112 | * The Grafana dashboard on http://localhost:3000
113 |
114 | ## Extra demo: e-Paper HAT
115 | If you have a Waveshare 2.7 inch three-colour e-Paper HAT, you can use this demo in combination with the [RuuviTag ePaper](https://github.com/koenvervloesem/ruuvitag-epaper) project on a Raspberry Pi:
116 |
117 | * Build the Docker container of that project.
118 | * Start this container together with the containers of the RuuviTag Demo: `docker-compose up -f docker-compose-epaper.yml up -d`.
119 |
120 | This shows the temperature and humidity measurements of the four configured RuuviTag sensors on the display, as well as the date, time and IP address. The latter is a nice way to know which IP address you have to log into to access the dashboards.
121 |
122 | ## Security
123 | This is purely a demo of how you can process RuuviTag sensor measurements, so there are no special security measures such as encryption, and minimal authentication and user permissions. Only use this demo for evaluation purposes.
124 |
125 | The following default passwords are configured after installation:
126 |
127 | * Node-RED dashboard: username **admin** and password **password**. To change this, run `docker exec -ti node-red /usr/local/bin/node -e "console.log(require('bcryptjs').hashSync(process.argv[1], 8));" your-password-here` with your new password instead of `your-password-here` and paste the output string in the line `password: "$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.",` after the line `username: "admin",` in the file `node-red/settings.js`. After this, restart Node-RED with `docker-compose restart node-red`.
128 | * Grafana: username **admin** and password **admin**. After the first login, you're asked to choose another password.
129 |
130 | If you want to know more about securing Mosquitto and Node-RED, please consult my book [Control Your Home with Raspberry Pi: Secure, Modular, Open-Source and Self-Sufficient](https://koen.vervloesem.eu/books/control-your-home-with-raspberry-pi/) and the accompanying GitHub repository [koenvervloesem/raspberry-pi-home-automation](https://github.com/koenvervloesem/raspberry-pi-home-automation).
131 |
132 | ## Stopping the demo
133 | If you want to stop the demo, just run:
134 |
135 | ```shell
136 | docker-compose down
137 | ```
138 |
139 | If you run the extra demo with the e-Paper HAT, stop the demo like this:
140 |
141 | ```shell
142 | docker-compose -f docker-compose-epaper.yml down
143 | ```
144 |
145 | ## Architecture
146 |
147 | This is the architecture of the demo:
148 |
149 | 
150 |
151 | This diagram shows two instances of `bt-mqtt-gateway`. You can use as many as you want, installed on Raspberry Pis or other devices positioned in multiple places for the best Bluetooth coverage of all sensors.
152 |
153 | While the demo installs all components on one device, you can distribute them over various devices. For instance, bt-mqtt-gateway on various receiver devices, ruuvitag-epaper on a Raspberry Pi with the Waveshare e-Paper HAT, HiveMQ MQTT Web Client on a developer laptop, and Mosquitto, Node-RED and Telegraf/InfluxDB/Grafana on a Linux server.
154 |
155 | ## License
156 | This program is provided by [Koen Vervloesem](mailto:koen@vervloesem.eu) as open source software with the MIT license. See the LICENSE file for more information.
157 |
--------------------------------------------------------------------------------
/ruuvitag-demo-diagram.dot:
--------------------------------------------------------------------------------
1 | digraph demo {
2 | compound=true
3 | node [shape=folder style=filled fillcolor="#438dd5"
4 | fontcolor=white fontsize=12 fontname="Helvetica Bold"]
5 | graph [ranksep=1.5 rankdir=LR]
6 | edge [style=solid]
7 |
8 | // RuuviTags
9 | "RuuviTag 1" [shape=doublecircle fillcolor=white fontcolor=black]
10 | "RuuviTag 4" [shape=doublecircle fillcolor=white fontcolor=black]
11 | "RuuviTag 3" [shape=doublecircle fillcolor=white fontcolor=black]
12 | "RuuviTag 2" [shape=doublecircle fillcolor=white fontcolor=black]
13 |
14 | // First bt-mqtt-gateway receiving RuuviTag broadcasts
15 | "RuuviTag 1" -> "ruuvitag-sensor1" [
16 | lhead="cluster_bt-mqtt-gateway1"
17 | style=dashed
18 | labeldistance=5
19 | labelangle=0
20 | label=<
21 |
26 | >
27 | ]
28 |
29 | "RuuviTag 2" -> "ruuvitag-sensor1" [
30 | lhead="cluster_bt-mqtt-gateway1"
31 | style=dashed
32 | labeldistance=5
33 | labelangle=0
34 | label=<
35 |
40 | >
41 | ]
42 |
43 | "RuuviTag 3" -> "ruuvitag-sensor1" [
44 | lhead="cluster_bt-mqtt-gateway1"
45 | style=dashed
46 | labeldistance=5
47 | labelangle=0
48 | label=<
49 |
54 | >
55 | ]
56 |
57 | "RuuviTag 4" -> "ruuvitag-sensor1" [
58 | lhead="cluster_bt-mqtt-gateway1"
59 | style=dashed
60 | labeldistance=5
61 | labelangle=0
62 | label=<
63 |
68 | >
69 | ]
70 |
71 | subgraph "cluster_bt-mqtt-gateway1" {
72 | label="bt-mqtt-gateway"
73 | style=filled
74 | fillcolor="#438dd5"
75 | fontcolor=white
76 | "ruuvitag-sensor1" [label="ruuvitag-sensor" shape=tab fillcolor="#399ba3"]
77 | }
78 |
79 | // Second bt-mqtt-gateway receiving RuuviTag broadcasts
80 | "RuuviTag 1" -> "ruuvitag-sensor2" [
81 | lhead="cluster_bt-mqtt-gateway2"
82 | style=dashed
83 | labeldistance=5
84 | labelangle=0
85 | label=<
86 |
91 | >
92 | ]
93 |
94 | "RuuviTag 2" -> "ruuvitag-sensor2" [
95 | lhead="cluster_bt-mqtt-gateway2"
96 | style=dashed
97 | labeldistance=5
98 | labelangle=0
99 | label=<
100 |
101 |
102 | | BLE |
103 |
104 |
105 | >
106 | ]
107 |
108 | "RuuviTag 3" -> "ruuvitag-sensor2" [
109 | lhead="cluster_bt-mqtt-gateway2"
110 | style=dashed
111 | labeldistance=5
112 | labelangle=0
113 | label=<
114 |
115 |
116 | | BLE |
117 |
118 |
119 | >
120 | ]
121 |
122 | "RuuviTag 4" -> "ruuvitag-sensor2" [
123 | lhead="cluster_bt-mqtt-gateway2"
124 | style=dashed
125 | labeldistance=5
126 | labelangle=0
127 | label=<
128 |
129 |
130 | | BLE |
131 |
132 |
133 | >
134 | ]
135 |
136 | subgraph "cluster_bt-mqtt-gateway2" {
137 | label="bt-mqtt-gateway"
138 | style=filled
139 | fillcolor="#438dd5"
140 | fontcolor=white
141 | "ruuvitag-sensor2" [label="ruuvitag-sensor" shape=tab fillcolor="#399ba3"]
142 | }
143 |
144 | // Mosquitto
145 | "ruuvitag-sensor1" -> Mosquitto [
146 | ltail="cluster_bt-mqtt-gateway1"
147 | labeldistance=5
148 | labelangle=0
149 | label=<
150 |
151 |
152 | | MQTT |
153 |
154 |
155 | >
156 | ]
157 |
158 | "ruuvitag-sensor2" -> Mosquitto [
159 | ltail="cluster_bt-mqtt-gateway2"
160 | labeldistance=5
161 | labelangle=0
162 | label=<
163 |
164 |
165 | | MQTT |
166 |
167 |
168 | >
169 | ]
170 |
171 | Mosquitto [shape=rect]
172 |
173 | // HiveMQT MQTT Web Client
174 | Mosquitto -> hivemq_web_client [
175 | lhead=cluster_hivemq
176 | labeldistance=5
177 | labelangle=0
178 | label=<
179 |
180 |
181 | | WebSockets |
182 |
183 |
184 | >
185 | ]
186 |
187 | subgraph cluster_hivemq {
188 | label="HiveMQ MQTT Web Client"
189 | style=filled
190 | fillcolor="#438dd5"
191 | fontcolor=white
192 | hivemq_web_client [label="Web client" fillcolor="#fcb338" fontcolor=black]
193 | }
194 |
195 | // ruuvitag-epaper
196 | Mosquitto -> epaper [
197 | lhead=cluster_epaper
198 | labeldistance=5
199 | labelangle=0
200 | label=<
201 |
202 |
203 | | MQTT |
204 |
205 |
206 | >
207 | ]
208 |
209 | subgraph cluster_epaper{
210 | label="ruuvitag-epaper"
211 | style=filled
212 | fillcolor="#438dd5"
213 | fontcolor=white
214 | "Paho MQTT" [shape=tab fillcolor="#399ba3"]
215 | "epd-library-python" [shape=tab fillcolor="#399ba3"]
216 | epaper [label="Waveshare e-Paper HAT" fillcolor="#fcb338" fontcolor=black]
217 | }
218 |
219 | // Node-RED
220 | Mosquitto -> "Node-RED_flow" [
221 | lhead="cluster_Node-RED"
222 | labeldistance=5
223 | labelangle=0
224 | label=<
225 |
226 |
227 | | MQTT |
228 |
229 |
230 | >
231 | ]
232 |
233 | subgraph "cluster_Node-RED" {
234 | label="Node-RED"
235 | style=filled
236 | fillcolor="#438dd5"
237 | fontcolor=white
238 | "Node-RED_flow" [label="Flow" fillcolor="#fcb338" fontcolor=black]
239 | "Node-RED_dashboard" [label="Dashboard" fillcolor="#fcb338" fontcolor=black]
240 | }
241 |
242 | // Grafana
243 | Mosquitto -> Telegraf [
244 | labeldistance=5
245 | labelangle=0
246 | label=<
247 |
248 |
249 | | MQTT |
250 |
251 |
252 | >
253 | ]
254 |
255 | Telegraf [shape=rect]
256 |
257 | Telegraf -> InfluxDB [
258 | labeldistance=5
259 | labelangle=0
260 | label=<
261 |
262 |
263 | | HTTP |
264 |
265 |
266 | >
267 | ]
268 |
269 | InfluxDB [shape=cylinder]
270 |
271 | InfluxDB -> Grafana_dashboard [
272 | lhead=cluster_Grafana
273 | labeldistance=5
274 | labelangle=0
275 | label=<
276 |
277 |
278 | | HTTP |
279 |
280 |
281 | >
282 | ]
283 |
284 | subgraph cluster_Grafana {
285 | label="Grafana"
286 | style=filled
287 | fillcolor="#438dd5"
288 | fontcolor=white
289 | Grafana_dashboard [label="Dashboard" fillcolor="#fcb338" fontcolor=black]
290 | }
291 | }
292 |
--------------------------------------------------------------------------------
/telegraf/telegraf.conf:
--------------------------------------------------------------------------------
1 | # Configuration for telegraf agent
2 | [agent]
3 | ## Default data collection interval for all inputs
4 | interval = "10s"
5 | ## Rounds collection interval to 'interval'
6 | ## ie, if interval="10s" then always collect on :00, :10, :20, etc.
7 | round_interval = true
8 |
9 | ## Telegraf will send metrics to outputs in batches of at most
10 | ## metric_batch_size metrics.
11 | ## This controls the size of writes that Telegraf sends to output plugins.
12 | metric_batch_size = 1000
13 |
14 | ## Maximum number of unwritten metrics per output.
15 | metric_buffer_limit = 10000
16 |
17 | ## Collection jitter is used to jitter the collection by a random amount.
18 | ## Each plugin will sleep for a random time within jitter before collecting.
19 | ## This can be used to avoid many plugins querying things like sysfs at the
20 | ## same time, which can have a measurable effect on the system.
21 | collection_jitter = "0s"
22 |
23 | ## Default flushing interval for all outputs. Maximum flush_interval will be
24 | ## flush_interval + flush_jitter
25 | flush_interval = "10s"
26 | ## Jitter the flush interval by a random amount. This is primarily to avoid
27 | ## large write spikes for users running a large number of telegraf instances.
28 | ## ie, a jitter of 5s and interval 10s means flushes will happen every 10-15s
29 | flush_jitter = "0s"
30 |
31 | ## By default or when set to "0s", precision will be set to the same
32 | ## timestamp order as the collection interval, with the maximum being 1s.
33 | ## ie, when interval = "10s", precision will be "1s"
34 | ## when interval = "250ms", precision will be "1ms"
35 | ## Precision will NOT be used for service inputs. It is up to each individual
36 | ## service input to set the timestamp at the appropriate precision.
37 | ## Valid time units are "ns", "us" (or "µs"), "ms", "s".
38 | precision = ""
39 |
40 | ## Log at debug level.
41 | # debug = false
42 | ## Log only error level messages.
43 | # quiet = false
44 |
45 | ## Log file name, the empty string means to log to stderr.
46 | # logfile = ""
47 |
48 | ## The logfile will be rotated after the time interval specified. When set
49 | ## to 0 no time based rotation is performed. Logs are rotated only when
50 | ## written to, if there is no log activity rotation may be delayed.
51 | # logfile_rotation_interval = "0d"
52 |
53 | ## The logfile will be rotated when it becomes larger than the specified
54 | ## size. When set to 0 no size based rotation is performed.
55 | # logfile_rotation_max_size = "0MB"
56 |
57 | ## Maximum number of rotated archives to keep, any older logs are deleted.
58 | ## If set to -1, no archives are removed.
59 | # logfile_rotation_max_archives = 5
60 |
61 | ## Override default hostname, if empty use os.Hostname()
62 | hostname = ""
63 | ## If set to true, do no set the "host" tag in the telegraf agent.
64 | omit_hostname = false
65 |
66 |
67 | ###############################################################################
68 | # OUTPUT PLUGINS #
69 | ###############################################################################
70 |
71 |
72 | # Configuration for sending metrics to InfluxDB
73 | [[outputs.influxdb]]
74 | ## The full HTTP or UDP URL for your InfluxDB instance.
75 | ##
76 | ## Multiple URLs can be specified for a single cluster, only ONE of the
77 | ## urls will be written to each interval.
78 | # urls = ["unix:///var/run/influxdb.sock"]
79 | # urls = ["udp://127.0.0.1:8089"]
80 | # urls = ["http://127.0.0.1:8086"]
81 | urls = ["http://influxdb:8086"]
82 |
83 | ## The target database for metrics; will be created as needed.
84 | ## For UDP url endpoint database needs to be configured on server side.
85 | database = "telegraf"
86 |
87 | ## The value of this tag will be used to determine the database. If this
88 | ## tag is not set the 'database' option is used as the default.
89 | # database_tag = ""
90 |
91 | ## If true, the database tag will not be added to the metric.
92 | # exclude_database_tag = false
93 |
94 | ## If true, no CREATE DATABASE queries will be sent. Set to true when using
95 | ## Telegraf with a user without permissions to create databases or when the
96 | ## database already exists.
97 | # skip_database_creation = false
98 |
99 | ## Name of existing retention policy to write to. Empty string writes to
100 | ## the default retention policy. Only takes effect when using HTTP.
101 | # retention_policy = ""
102 |
103 | ## Write consistency (clusters only), can be: "any", "one", "quorum", "all".
104 | ## Only takes effect when using HTTP.
105 | # write_consistency = "any"
106 |
107 | ## Timeout for HTTP messages.
108 | # timeout = "5s"
109 |
110 | ## HTTP Basic Auth
111 | # username = "telegraf"
112 | # password = "metricsmetricsmetricsmetrics"
113 |
114 | ## HTTP User-Agent
115 | # user_agent = "telegraf"
116 |
117 | ## UDP payload size is the maximum packet size to send.
118 | # udp_payload = "512B"
119 |
120 | ## Optional TLS Config for use on HTTP connections.
121 | # tls_ca = "/etc/telegraf/ca.pem"
122 | # tls_cert = "/etc/telegraf/cert.pem"
123 | # tls_key = "/etc/telegraf/key.pem"
124 | ## Use TLS but skip chain & host verification
125 | # insecure_skip_verify = false
126 |
127 | ## HTTP Proxy override, if unset values the standard proxy environment
128 | ## variables are consulted to determine which proxy, if any, should be used.
129 | # http_proxy = "http://corporate.proxy:3128"
130 |
131 | ## Additional HTTP headers
132 | # http_headers = {"X-Special-Header" = "Special-Value"}
133 |
134 | ## HTTP Content-Encoding for write request body, can be set to "gzip" to
135 | ## compress body or "identity" to apply no encoding.
136 | # content_encoding = "identity"
137 |
138 | ## When true, Telegraf will output unsigned integers as unsigned values,
139 | ## i.e.: "42u". You will need a version of InfluxDB supporting unsigned
140 | ## integer values. Enabling this option will result in field type errors if
141 | ## existing data has been written.
142 | # influx_uint_support = false
143 |
144 |
145 | ###############################################################################
146 | # SERVICE INPUT PLUGINS #
147 | ###############################################################################
148 |
149 |
150 | # Read metrics from MQTT topic(s)
151 | [[inputs.mqtt_consumer]]
152 | ## MQTT broker URLs to be used. The format should be scheme://host:port,
153 | ## schema can be tcp, ssl, or ws.
154 | servers = ["tcp://mosquitto:1883"]
155 |
156 | ## Topics that will be subscribed to.
157 | topics = [
158 | "bt-mqtt-gateway/ruuvitag/#",
159 | ]
160 |
161 | ## The message topic will be stored in a tag specified by this value. If set
162 | ## to the empty string no topic tag will be created.
163 | topic_tag = "topic"
164 |
165 | ## QoS policy for messages
166 | ## 0 = at most once
167 | ## 1 = at least once
168 | ## 2 = exactly once
169 | ##
170 | ## When using a QoS of 1 or 2, you should enable persistent_session to allow
171 | ## resuming unacknowledged messages.
172 | # qos = 0
173 |
174 | ## Connection timeout for initial connection in seconds
175 | # connection_timeout = "30s"
176 |
177 | ## Maximum messages to read from the broker that have not been written by an
178 | ## output. For best throughput set based on the number of metrics within
179 | ## each message and the size of the output's metric_batch_size.
180 | ##
181 | ## For example, if each message from the queue contains 10 metrics and the
182 | ## output metric_batch_size is 1000, setting this to 100 will ensure that a
183 | ## full batch is collected and the write is triggered immediately without
184 | ## waiting until the next flush_interval.
185 | # max_undelivered_messages = 1000
186 |
187 | ## Persistent session disables clearing of the client session on connection.
188 | ## In order for this option to work you must also set client_id to identity
189 | ## the client. To receive messages that arrived while the client is offline,
190 | ## also set the qos option to 1 or 2 and don't forget to also set the QoS when
191 | ## publishing.
192 | # persistent_session = false
193 |
194 | ## If unset, a random client ID will be generated.
195 | client_id = "telegraf"
196 |
197 | ## Username and password to connect MQTT server.
198 | # username = "telegraf"
199 | # password = "metricsmetricsmetricsmetrics"
200 |
201 | ## Optional TLS Config
202 | # tls_ca = "/etc/telegraf/ca.pem"
203 | # tls_cert = "/etc/telegraf/cert.pem"
204 | # tls_key = "/etc/telegraf/key.pem"
205 | ## Use TLS but skip chain & host verification
206 | # insecure_skip_verify = false
207 |
208 | ## Data format to consume.
209 | ## Each data format has its own unique set of configuration options, read
210 | ## more about them here:
211 | ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md
212 | data_format = "value"
213 | data_type = "float"
214 |
215 | name_override = "ruuvitag"
216 |
--------------------------------------------------------------------------------
/node-red/settings.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright JS Foundation and other contributors, http://js.foundation
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | **/
16 |
17 | // The `https` setting requires the `fs` module. Uncomment the following
18 | // to make it available:
19 | //var fs = require("fs");
20 |
21 | module.exports = {
22 | // the tcp port that the Node-RED web server is listening on
23 | uiPort: process.env.PORT || 1880,
24 |
25 | // By default, the Node-RED UI accepts connections on all IPv4 interfaces.
26 | // To listen on all IPv6 addresses, set uiHost to "::",
27 | // The following property can be used to listen on a specific interface. For
28 | // example, the following would only allow connections from the local machine.
29 | //uiHost: "127.0.0.1",
30 |
31 | // Retry time in milliseconds for MQTT connections
32 | mqttReconnectTime: 15000,
33 |
34 | // Retry time in milliseconds for Serial port connections
35 | serialReconnectTime: 15000,
36 |
37 | // Retry time in milliseconds for TCP socket connections
38 | //socketReconnectTime: 10000,
39 |
40 | // Timeout in milliseconds for TCP server socket connections
41 | // defaults to no timeout
42 | //socketTimeout: 120000,
43 |
44 | // Maximum number of messages to wait in queue while attempting to connect to TCP socket
45 | // defaults to 1000
46 | //tcpMsgQueueSize: 2000,
47 |
48 | // Timeout in milliseconds for HTTP request connections
49 | // defaults to 120 seconds
50 | //httpRequestTimeout: 120000,
51 |
52 | // The maximum length, in characters, of any message sent to the debug sidebar tab
53 | debugMaxLength: 1000,
54 |
55 | // The maximum number of messages nodes will buffer internally as part of their
56 | // operation. This applies across a range of nodes that operate on message sequences.
57 | // defaults to no limit. A value of 0 also means no limit is applied.
58 | //nodeMessageBufferMaxLength: 0,
59 |
60 | // To disable the option for using local files for storing keys and certificates in the TLS configuration
61 | // node, set this to true
62 | //tlsConfigDisableLocalFiles: true,
63 |
64 | // Colourise the console output of the debug node
65 | //debugUseColors: true,
66 |
67 | // The file containing the flows. If not set, it defaults to flows_.json
68 | //flowFile: 'flows.json',
69 |
70 | // To enabled pretty-printing of the flow within the flow file, set the following
71 | // property to true:
72 | //flowFilePretty: true,
73 |
74 | // By default, credentials are encrypted in storage using a generated key. To
75 | // specify your own secret, set the following property.
76 | // If you want to disable encryption of credentials, set this property to false.
77 | // Note: once you set this property, do not change it - doing so will prevent
78 | // node-red from being able to decrypt your existing credentials and they will be
79 | // lost.
80 | //credentialSecret: "a-secret-key",
81 |
82 | // By default, all user data is stored in a directory called `.node-red` under
83 | // the user's home directory. To use a different location, the following
84 | // property can be used
85 | //userDir: '/home/nol/.node-red/',
86 |
87 | // Node-RED scans the `nodes` directory in the userDir to find local node files.
88 | // The following property can be used to specify an additional directory to scan.
89 | //nodesDir: '/home/nol/.node-red/nodes',
90 |
91 | // By default, the Node-RED UI is available at http://localhost:1880/
92 | // The following property can be used to specify a different root path.
93 | // If set to false, this is disabled.
94 | //httpAdminRoot: '/admin',
95 |
96 | // Some nodes, such as HTTP In, can be used to listen for incoming http requests.
97 | // By default, these are served relative to '/'. The following property
98 | // can be used to specifiy a different root path. If set to false, this is
99 | // disabled.
100 | //httpNodeRoot: '/red-nodes',
101 |
102 | // The following property can be used in place of 'httpAdminRoot' and 'httpNodeRoot',
103 | // to apply the same root to both parts.
104 | //httpRoot: '/red',
105 |
106 | // When httpAdminRoot is used to move the UI to a different root path, the
107 | // following property can be used to identify a directory of static content
108 | // that should be served at http://localhost:1880/.
109 | //httpStatic: '/home/nol/node-red-static/',
110 |
111 | // The maximum size of HTTP request that will be accepted by the runtime api.
112 | // Default: 5mb
113 | //apiMaxLength: '5mb',
114 |
115 | // If you installed the optional node-red-dashboard you can set it's path
116 | // relative to httpRoot
117 | //ui: { path: "ui" },
118 |
119 | // Securing Node-RED
120 | // -----------------
121 | // To password protect the Node-RED editor and admin API, the following
122 | // property can be used. See http://nodered.org/docs/security.html for details.
123 | adminAuth: {
124 | type: "credentials",
125 | users: [{
126 | username: "admin",
127 | password: "$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.",
128 | permissions: "*"
129 | }]
130 | },
131 |
132 | // To password protect the node-defined HTTP endpoints (httpNodeRoot), or
133 | // the static content (httpStatic), the following properties can be used.
134 | // The pass field is a bcrypt hash of the password.
135 | // See http://nodered.org/docs/security.html#generating-the-password-hash
136 | //httpNodeAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."},
137 | //httpStaticAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."},
138 |
139 | // The following property can be used to enable HTTPS
140 | // See http://nodejs.org/api/https.html#https_https_createserver_options_requestlistener
141 | // for details on its contents.
142 | // See the comment at the top of this file on how to load the `fs` module used by
143 | // this setting.
144 | //
145 | //https: {
146 | // key: fs.readFileSync('privatekey.pem'),
147 | // cert: fs.readFileSync('certificate.pem')
148 | //},
149 |
150 | // The following property can be used to cause insecure HTTP connections to
151 | // be redirected to HTTPS.
152 | //requireHttps: true,
153 |
154 | // The following property can be used to disable the editor. The admin API
155 | // is not affected by this option. To disable both the editor and the admin
156 | // API, use either the httpRoot or httpAdminRoot properties
157 | //disableEditor: false,
158 |
159 | // The following property can be used to configure cross-origin resource sharing
160 | // in the HTTP nodes.
161 | // See https://github.com/troygoode/node-cors#configuration-options for
162 | // details on its contents. The following is a basic permissive set of options:
163 | //httpNodeCors: {
164 | // origin: "*",
165 | // methods: "GET,PUT,POST,DELETE"
166 | //},
167 |
168 | // If you need to set an http proxy please set an environment variable
169 | // called http_proxy (or HTTP_PROXY) outside of Node-RED in the operating system.
170 | // For example - http_proxy=http://myproxy.com:8080
171 | // (Setting it here will have no effect)
172 | // You may also specify no_proxy (or NO_PROXY) to supply a comma separated
173 | // list of domains to not proxy, eg - no_proxy=.acme.co,.acme.co.uk
174 |
175 | // The following property can be used to add a custom middleware function
176 | // in front of all http in nodes. This allows custom authentication to be
177 | // applied to all http in nodes, or any other sort of common request processing.
178 | //httpNodeMiddleware: function(req,res,next) {
179 | // // Handle/reject the request, or pass it on to the http in node by calling next();
180 | // // Optionally skip our rawBodyParser by setting this to true;
181 | // //req.skipRawBodyParser = true;
182 | // next();
183 | //},
184 |
185 | // The following property can be used to pass custom options to the Express.js
186 | // server used by Node-RED. For a full list of available options, refer
187 | // to http://expressjs.com/en/api.html#app.settings.table
188 | //httpServerOptions: { },
189 |
190 | // The following property can be used to verify websocket connection attempts.
191 | // This allows, for example, the HTTP request headers to be checked to ensure
192 | // they include valid authentication information.
193 | //webSocketNodeVerifyClient: function(info) {
194 | // // 'info' has three properties:
195 | // // - origin : the value in the Origin header
196 | // // - req : the HTTP request
197 | // // - secure : true if req.connection.authorized or req.connection.encrypted is set
198 | // //
199 | // // The function should return true if the connection should be accepted, false otherwise.
200 | // //
201 | // // Alternatively, if this function is defined to accept a second argument, callback,
202 | // // it can be used to verify the client asynchronously.
203 | // // The callback takes three arguments:
204 | // // - result : boolean, whether to accept the connection or not
205 | // // - code : if result is false, the HTTP error status to return
206 | // // - reason: if result is false, the HTTP reason string to return
207 | //},
208 |
209 | // The following property can be used to seed Global Context with predefined
210 | // values. This allows extra node modules to be made available with the
211 | // Function node.
212 | // For example,
213 | // functionGlobalContext: { os:require('os') }
214 | // can be accessed in a function block as:
215 | // global.get("os")
216 | functionGlobalContext: {
217 | // os:require('os'),
218 | // jfive:require("johnny-five"),
219 | // j5board:require("johnny-five").Board({repl:false})
220 | },
221 | // `global.keys()` returns a list of all properties set in global context.
222 | // This allows them to be displayed in the Context Sidebar within the editor.
223 | // In some circumstances it is not desirable to expose them to the editor. The
224 | // following property can be used to hide any property set in `functionGlobalContext`
225 | // from being list by `global.keys()`.
226 | // By default, the property is set to false to avoid accidental exposure of
227 | // their values. Setting this to true will cause the keys to be listed.
228 | exportGlobalContextKeys: false,
229 |
230 |
231 | // Context Storage
232 | // The following property can be used to enable context storage. The configuration
233 | // provided here will enable file-based context that flushes to disk every 30 seconds.
234 | // Refer to the documentation for further options: https://nodered.org/docs/api/context/
235 | //
236 | //contextStorage: {
237 | // default: {
238 | // module:"localfilesystem"
239 | // },
240 | //},
241 |
242 | // The following property can be used to order the categories in the editor
243 | // palette. If a node's category is not in the list, the category will get
244 | // added to the end of the palette.
245 | // If not set, the following default order is used:
246 | //paletteCategories: ['subflows','flow','input','output','function','parser','social','mobile','storage','analysis','advanced'],
247 |
248 | // Configure the logging output
249 | logging: {
250 | // Only console logging is currently supported
251 | console: {
252 | // Level of logging to be recorded. Options are:
253 | // fatal - only those errors which make the application unusable should be recorded
254 | // error - record errors which are deemed fatal for a particular request + fatal errors
255 | // warn - record problems which are non fatal + errors + fatal errors
256 | // info - record information about the general running of the application + warn + error + fatal errors
257 | // debug - record information which is more verbose than info + info + warn + error + fatal errors
258 | // trace - record very detailed logging + debug + info + warn + error + fatal errors
259 | // off - turn off all logging (doesn't affect metrics or audit)
260 | level: "info",
261 | // Whether or not to include metric events in the log output
262 | metrics: false,
263 | // Whether or not to include audit events in the log output
264 | audit: false
265 | }
266 | },
267 |
268 | // Customising the editor
269 | editorTheme: {
270 | projects: {
271 | // To enable the Projects feature, set this value to true
272 | enabled: false
273 | }
274 | }
275 | }
276 |
--------------------------------------------------------------------------------
/node-red/flows.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "eaed8fa5.46ccc8",
4 | "type": "tab",
5 | "label": "RuuviTag Demo",
6 | "disabled": false,
7 | "info": ""
8 | },
9 | {
10 | "id": "d1ce6ba9.c90f2",
11 | "type": "mqtt-broker",
12 | "z": "",
13 | "name": "mosquitto",
14 | "broker": "mosquitto",
15 | "port": "1883",
16 | "clientid": "node-red",
17 | "usetls": false,
18 | "compatmode": false,
19 | "keepalive": "60",
20 | "cleansession": true,
21 | "birthTopic": "",
22 | "birthQos": "0",
23 | "birthPayload": "",
24 | "closeTopic": "",
25 | "closeQos": "0",
26 | "closePayload": "",
27 | "willTopic": "",
28 | "willQos": "0",
29 | "willPayload": ""
30 | },
31 | {
32 | "id": "58b18a79.6e4324",
33 | "type": "ui_tab",
34 | "z": "",
35 | "name": "RuuviTag demo",
36 | "icon": "dashboard",
37 | "disabled": false,
38 | "hidden": false
39 | },
40 | {
41 | "id": "4f008f1d.e39768",
42 | "type": "ui_group",
43 | "z": "",
44 | "name": "RuuviTag 1",
45 | "tab": "58b18a79.6e4324",
46 | "disp": true,
47 | "width": "6",
48 | "collapse": false
49 | },
50 | {
51 | "id": "2b14eefe.3ed422",
52 | "type": "ui_base",
53 | "theme": {
54 | "name": "theme-light",
55 | "lightTheme": {
56 | "default": "#0094CE",
57 | "baseColor": "#0094CE",
58 | "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif",
59 | "edited": true,
60 | "reset": false
61 | },
62 | "darkTheme": {
63 | "default": "#097479",
64 | "baseColor": "#097479",
65 | "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif",
66 | "edited": false
67 | },
68 | "customTheme": {
69 | "name": "Untitled Theme 1",
70 | "default": "#4B7930",
71 | "baseColor": "#4B7930",
72 | "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif"
73 | },
74 | "themeState": {
75 | "base-color": {
76 | "default": "#0094CE",
77 | "value": "#0094CE",
78 | "edited": false
79 | },
80 | "page-titlebar-backgroundColor": {
81 | "value": "#0094CE",
82 | "edited": false
83 | },
84 | "page-backgroundColor": {
85 | "value": "#fafafa",
86 | "edited": false
87 | },
88 | "page-sidebar-backgroundColor": {
89 | "value": "#ffffff",
90 | "edited": false
91 | },
92 | "group-textColor": {
93 | "value": "#1bbfff",
94 | "edited": false
95 | },
96 | "group-borderColor": {
97 | "value": "#ffffff",
98 | "edited": false
99 | },
100 | "group-backgroundColor": {
101 | "value": "#ffffff",
102 | "edited": false
103 | },
104 | "widget-textColor": {
105 | "value": "#111111",
106 | "edited": false
107 | },
108 | "widget-backgroundColor": {
109 | "value": "#0094ce",
110 | "edited": false
111 | },
112 | "widget-borderColor": {
113 | "value": "#ffffff",
114 | "edited": false
115 | },
116 | "base-font": {
117 | "value": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif"
118 | }
119 | },
120 | "angularTheme": {
121 | "primary": "indigo",
122 | "accents": "blue",
123 | "warn": "red",
124 | "background": "grey"
125 | }
126 | },
127 | "site": {
128 | "name": "Node-RED Dashboard",
129 | "hideToolbar": "false",
130 | "allowSwipe": "false",
131 | "lockMenu": "false",
132 | "allowTempTheme": "true",
133 | "dateFormat": "DD/MM/YYYY",
134 | "sizes": {
135 | "sx": 48,
136 | "sy": 48,
137 | "gx": 6,
138 | "gy": 6,
139 | "cx": 6,
140 | "cy": 6,
141 | "px": 0,
142 | "py": 0
143 | }
144 | }
145 | },
146 | {
147 | "id": "7e2d42c6.4b1d84",
148 | "type": "ui_group",
149 | "z": "",
150 | "name": "RuuviTag 2",
151 | "tab": "58b18a79.6e4324",
152 | "disp": true,
153 | "width": "6",
154 | "collapse": false
155 | },
156 | {
157 | "id": "c13387c.ae43bf8",
158 | "type": "ui_group",
159 | "z": "",
160 | "name": "RuuviTag 3",
161 | "tab": "58b18a79.6e4324",
162 | "disp": true,
163 | "width": "6",
164 | "collapse": false
165 | },
166 | {
167 | "id": "30b8e062.37b95",
168 | "type": "ui_group",
169 | "z": "",
170 | "name": "RuuviTag 4",
171 | "tab": "58b18a79.6e4324",
172 | "disp": true,
173 | "width": "6",
174 | "collapse": false
175 | },
176 | {
177 | "id": "f1499505.163d08",
178 | "type": "mqtt in",
179 | "z": "eaed8fa5.46ccc8",
180 | "name": "",
181 | "topic": "bt-mqtt-gateway/ruuvitag/tag1/temperature",
182 | "qos": "2",
183 | "datatype": "auto",
184 | "broker": "d1ce6ba9.c90f2",
185 | "x": 350,
186 | "y": 40,
187 | "wires": [
188 | [
189 | "3ed4e927.0d7556"
190 | ]
191 | ]
192 | },
193 | {
194 | "id": "3ed4e927.0d7556",
195 | "type": "ui_gauge",
196 | "z": "eaed8fa5.46ccc8",
197 | "name": "RuuviTag 1 temperature",
198 | "group": "4f008f1d.e39768",
199 | "order": 0,
200 | "width": 0,
201 | "height": 0,
202 | "gtype": "gage",
203 | "title": "Temperature",
204 | "label": "\u00b0C",
205 | "format": "{{value}}",
206 | "min": "-40",
207 | "max": "85",
208 | "colors": [
209 | "#00b500",
210 | "#e6e600",
211 | "#ca3838"
212 | ],
213 | "seg1": "",
214 | "seg2": "",
215 | "x": 910,
216 | "y": 40,
217 | "wires": []
218 | },
219 | {
220 | "id": "e95f5697.571e",
221 | "type": "mqtt in",
222 | "z": "eaed8fa5.46ccc8",
223 | "name": "",
224 | "topic": "bt-mqtt-gateway/ruuvitag/tag2/temperature",
225 | "qos": "2",
226 | "datatype": "auto",
227 | "broker": "d1ce6ba9.c90f2",
228 | "x": 350,
229 | "y": 440,
230 | "wires": [
231 | [
232 | "863e1b87.45c8c"
233 | ]
234 | ]
235 | },
236 | {
237 | "id": "863e1b87.45c8c",
238 | "type": "ui_gauge",
239 | "z": "eaed8fa5.46ccc8",
240 | "name": "RuuviTag 2 temperature",
241 | "group": "7e2d42c6.4b1d84",
242 | "order": 0,
243 | "width": 0,
244 | "height": 0,
245 | "gtype": "gage",
246 | "title": "Temperature",
247 | "label": "\u00b0C",
248 | "format": "{{value}}",
249 | "min": "-40",
250 | "max": "85",
251 | "colors": [
252 | "#00b500",
253 | "#e6e600",
254 | "#ca3838"
255 | ],
256 | "seg1": "",
257 | "seg2": "",
258 | "x": 930,
259 | "y": 440,
260 | "wires": []
261 | },
262 | {
263 | "id": "c1d1a418.33d548",
264 | "type": "mqtt in",
265 | "z": "eaed8fa5.46ccc8",
266 | "name": "",
267 | "topic": "bt-mqtt-gateway/ruuvitag/tag3/temperature",
268 | "qos": "2",
269 | "datatype": "auto",
270 | "broker": "d1ce6ba9.c90f2",
271 | "x": 350,
272 | "y": 880,
273 | "wires": [
274 | [
275 | "c86ed7a7.4c4cc8"
276 | ]
277 | ]
278 | },
279 | {
280 | "id": "c86ed7a7.4c4cc8",
281 | "type": "ui_gauge",
282 | "z": "eaed8fa5.46ccc8",
283 | "name": "RuuviTag 3 temperature",
284 | "group": "c13387c.ae43bf8",
285 | "order": 0,
286 | "width": 0,
287 | "height": 0,
288 | "gtype": "gage",
289 | "title": "Temperature",
290 | "label": "\u00b0C",
291 | "format": "{{value}}",
292 | "min": "-40",
293 | "max": "85",
294 | "colors": [
295 | "#00b500",
296 | "#e6e600",
297 | "#ca3838"
298 | ],
299 | "seg1": "",
300 | "seg2": "",
301 | "x": 930,
302 | "y": 880,
303 | "wires": []
304 | },
305 | {
306 | "id": "f47cc3f8.8913b",
307 | "type": "mqtt in",
308 | "z": "eaed8fa5.46ccc8",
309 | "name": "",
310 | "topic": "bt-mqtt-gateway/ruuvitag/tag1/humidity",
311 | "qos": "2",
312 | "datatype": "auto",
313 | "broker": "d1ce6ba9.c90f2",
314 | "x": 330,
315 | "y": 100,
316 | "wires": [
317 | [
318 | "5c188f09.7ed5b8"
319 | ]
320 | ]
321 | },
322 | {
323 | "id": "5c188f09.7ed5b8",
324 | "type": "ui_gauge",
325 | "z": "eaed8fa5.46ccc8",
326 | "name": "RuuviTag 1 humidity",
327 | "group": "4f008f1d.e39768",
328 | "order": 0,
329 | "width": 0,
330 | "height": 0,
331 | "gtype": "gage",
332 | "title": "Humidity",
333 | "label": "%",
334 | "format": "{{value}}",
335 | "min": 0,
336 | "max": "100",
337 | "colors": [
338 | "#00b500",
339 | "#e6e600",
340 | "#ca3838"
341 | ],
342 | "seg1": "",
343 | "seg2": "",
344 | "x": 900,
345 | "y": 100,
346 | "wires": []
347 | },
348 | {
349 | "id": "ffc8e29a.853b78",
350 | "type": "mqtt in",
351 | "z": "eaed8fa5.46ccc8",
352 | "name": "",
353 | "topic": "bt-mqtt-gateway/ruuvitag/tag2/humidity",
354 | "qos": "2",
355 | "datatype": "auto",
356 | "broker": "d1ce6ba9.c90f2",
357 | "x": 330,
358 | "y": 497,
359 | "wires": [
360 | [
361 | "9ccc8cf6.004788"
362 | ]
363 | ]
364 | },
365 | {
366 | "id": "9ccc8cf6.004788",
367 | "type": "ui_gauge",
368 | "z": "eaed8fa5.46ccc8",
369 | "name": "RuuviTag 2 humidity",
370 | "group": "7e2d42c6.4b1d84",
371 | "order": 0,
372 | "width": 0,
373 | "height": 0,
374 | "gtype": "gage",
375 | "title": "Humidity",
376 | "label": "%",
377 | "format": "{{value}}",
378 | "min": 0,
379 | "max": "100",
380 | "colors": [
381 | "#00b500",
382 | "#e6e600",
383 | "#ca3838"
384 | ],
385 | "seg1": "",
386 | "seg2": "",
387 | "x": 920,
388 | "y": 500,
389 | "wires": []
390 | },
391 | {
392 | "id": "3ef2487b.065738",
393 | "type": "mqtt in",
394 | "z": "eaed8fa5.46ccc8",
395 | "name": "",
396 | "topic": "bt-mqtt-gateway/ruuvitag/tag3/humidity",
397 | "qos": "2",
398 | "datatype": "auto",
399 | "broker": "d1ce6ba9.c90f2",
400 | "x": 330,
401 | "y": 940,
402 | "wires": [
403 | [
404 | "a5468b5a.6e6cd8"
405 | ]
406 | ]
407 | },
408 | {
409 | "id": "a5468b5a.6e6cd8",
410 | "type": "ui_gauge",
411 | "z": "eaed8fa5.46ccc8",
412 | "name": "RuuviTag 3 humidity",
413 | "group": "c13387c.ae43bf8",
414 | "order": 0,
415 | "width": 0,
416 | "height": 0,
417 | "gtype": "gage",
418 | "title": "Humidity",
419 | "label": "%",
420 | "format": "{{value}}",
421 | "min": 0,
422 | "max": "100",
423 | "colors": [
424 | "#00b500",
425 | "#e6e600",
426 | "#ca3838"
427 | ],
428 | "seg1": "",
429 | "seg2": "",
430 | "x": 920,
431 | "y": 940,
432 | "wires": []
433 | },
434 | {
435 | "id": "d75e46c0.9b16",
436 | "type": "mqtt in",
437 | "z": "eaed8fa5.46ccc8",
438 | "name": "",
439 | "topic": "bt-mqtt-gateway/ruuvitag/tag1/acceleration_z",
440 | "qos": "2",
441 | "datatype": "auto",
442 | "broker": "d1ce6ba9.c90f2",
443 | "x": 350,
444 | "y": 280,
445 | "wires": [
446 | [
447 | "b6dfc13d.c02ce"
448 | ]
449 | ]
450 | },
451 | {
452 | "id": "b6dfc13d.c02ce",
453 | "type": "switch",
454 | "z": "eaed8fa5.46ccc8",
455 | "name": "",
456 | "property": "payload",
457 | "propertyType": "msg",
458 | "rules": [
459 | {
460 | "t": "gt",
461 | "v": "50",
462 | "vt": "num"
463 | },
464 | {
465 | "t": "lt",
466 | "v": "-50",
467 | "vt": "num"
468 | },
469 | {
470 | "t": "btwn",
471 | "v": "-50",
472 | "vt": "num",
473 | "v2": "50",
474 | "v2t": "num"
475 | }
476 | ],
477 | "checkall": "true",
478 | "repair": false,
479 | "outputs": 3,
480 | "x": 670,
481 | "y": 280,
482 | "wires": [
483 | [
484 | "a2d62a5b.33809"
485 | ],
486 | [
487 | "30946de0.a6ddc2"
488 | ],
489 | [
490 | "3cbc8c7f.56a264"
491 | ]
492 | ]
493 | },
494 | {
495 | "id": "a2d62a5b.33809",
496 | "type": "change",
497 | "z": "eaed8fa5.46ccc8",
498 | "name": "",
499 | "rules": [
500 | {
501 | "t": "set",
502 | "p": "payload",
503 | "pt": "msg",
504 | "to": "Right side up",
505 | "tot": "str"
506 | }
507 | ],
508 | "action": "",
509 | "property": "",
510 | "from": "",
511 | "to": "",
512 | "reg": false,
513 | "x": 930,
514 | "y": 220,
515 | "wires": [
516 | [
517 | "d98a3ee6.b96258"
518 | ]
519 | ]
520 | },
521 | {
522 | "id": "30946de0.a6ddc2",
523 | "type": "change",
524 | "z": "eaed8fa5.46ccc8",
525 | "name": "",
526 | "rules": [
527 | {
528 | "t": "set",
529 | "p": "payload",
530 | "pt": "msg",
531 | "to": "Upside down",
532 | "tot": "str"
533 | }
534 | ],
535 | "action": "",
536 | "property": "",
537 | "from": "",
538 | "to": "",
539 | "reg": false,
540 | "x": 930,
541 | "y": 280,
542 | "wires": [
543 | [
544 | "d98a3ee6.b96258"
545 | ]
546 | ]
547 | },
548 | {
549 | "id": "3cbc8c7f.56a264",
550 | "type": "change",
551 | "z": "eaed8fa5.46ccc8",
552 | "name": "",
553 | "rules": [
554 | {
555 | "t": "set",
556 | "p": "payload",
557 | "pt": "msg",
558 | "to": "On its side",
559 | "tot": "str"
560 | }
561 | ],
562 | "action": "",
563 | "property": "",
564 | "from": "",
565 | "to": "",
566 | "reg": false,
567 | "x": 930,
568 | "y": 340,
569 | "wires": [
570 | [
571 | "d98a3ee6.b96258"
572 | ]
573 | ]
574 | },
575 | {
576 | "id": "d98a3ee6.b96258",
577 | "type": "ui_text",
578 | "z": "eaed8fa5.46ccc8",
579 | "group": "4f008f1d.e39768",
580 | "order": 2,
581 | "width": 0,
582 | "height": 0,
583 | "name": "",
584 | "label": "Orientation",
585 | "format": "{{msg.payload}}",
586 | "layout": "row-spread",
587 | "x": 1220,
588 | "y": 280,
589 | "wires": []
590 | },
591 | {
592 | "id": "2d4ac8e9.1ad118",
593 | "type": "mqtt in",
594 | "z": "eaed8fa5.46ccc8",
595 | "name": "",
596 | "topic": "bt-mqtt-gateway/ruuvitag/tag3/acceleration_z",
597 | "qos": "2",
598 | "datatype": "auto",
599 | "broker": "d1ce6ba9.c90f2",
600 | "x": 350,
601 | "y": 1140,
602 | "wires": [
603 | [
604 | "540a5152.08973"
605 | ]
606 | ]
607 | },
608 | {
609 | "id": "540a5152.08973",
610 | "type": "switch",
611 | "z": "eaed8fa5.46ccc8",
612 | "name": "",
613 | "property": "payload",
614 | "propertyType": "msg",
615 | "rules": [
616 | {
617 | "t": "gt",
618 | "v": "50",
619 | "vt": "num"
620 | },
621 | {
622 | "t": "lt",
623 | "v": "-50",
624 | "vt": "num"
625 | },
626 | {
627 | "t": "btwn",
628 | "v": "-50",
629 | "vt": "num",
630 | "v2": "50",
631 | "v2t": "num"
632 | }
633 | ],
634 | "checkall": "true",
635 | "repair": false,
636 | "outputs": 3,
637 | "x": 670,
638 | "y": 1140,
639 | "wires": [
640 | [
641 | "c807a1cb.f58a98"
642 | ],
643 | [
644 | "659f934e.708a44"
645 | ],
646 | [
647 | "84b4252c.842c9"
648 | ]
649 | ]
650 | },
651 | {
652 | "id": "c807a1cb.f58a98",
653 | "type": "change",
654 | "z": "eaed8fa5.46ccc8",
655 | "name": "",
656 | "rules": [
657 | {
658 | "t": "set",
659 | "p": "payload",
660 | "pt": "msg",
661 | "to": "Right side up",
662 | "tot": "str"
663 | }
664 | ],
665 | "action": "",
666 | "property": "",
667 | "from": "",
668 | "to": "",
669 | "reg": false,
670 | "x": 930,
671 | "y": 1080,
672 | "wires": [
673 | [
674 | "85e4d15e.9b3ae"
675 | ]
676 | ]
677 | },
678 | {
679 | "id": "659f934e.708a44",
680 | "type": "change",
681 | "z": "eaed8fa5.46ccc8",
682 | "name": "",
683 | "rules": [
684 | {
685 | "t": "set",
686 | "p": "payload",
687 | "pt": "msg",
688 | "to": "Upside down",
689 | "tot": "str"
690 | }
691 | ],
692 | "action": "",
693 | "property": "",
694 | "from": "",
695 | "to": "",
696 | "reg": false,
697 | "x": 930,
698 | "y": 1140,
699 | "wires": [
700 | [
701 | "85e4d15e.9b3ae"
702 | ]
703 | ]
704 | },
705 | {
706 | "id": "84b4252c.842c9",
707 | "type": "change",
708 | "z": "eaed8fa5.46ccc8",
709 | "name": "",
710 | "rules": [
711 | {
712 | "t": "set",
713 | "p": "payload",
714 | "pt": "msg",
715 | "to": "On its side",
716 | "tot": "str"
717 | }
718 | ],
719 | "action": "",
720 | "property": "",
721 | "from": "",
722 | "to": "",
723 | "reg": false,
724 | "x": 930,
725 | "y": 1200,
726 | "wires": [
727 | [
728 | "85e4d15e.9b3ae"
729 | ]
730 | ]
731 | },
732 | {
733 | "id": "85e4d15e.9b3ae",
734 | "type": "ui_text",
735 | "z": "eaed8fa5.46ccc8",
736 | "group": "c13387c.ae43bf8",
737 | "order": 2,
738 | "width": 0,
739 | "height": 0,
740 | "name": "",
741 | "label": "Orientation",
742 | "format": "{{msg.payload}}",
743 | "layout": "row-spread",
744 | "x": 1220,
745 | "y": 1140,
746 | "wires": []
747 | },
748 | {
749 | "id": "77c9b0e4.3f5b38",
750 | "type": "mqtt in",
751 | "z": "eaed8fa5.46ccc8",
752 | "name": "",
753 | "topic": "bt-mqtt-gateway/ruuvitag/tag2/acceleration_z",
754 | "qos": "2",
755 | "datatype": "auto",
756 | "broker": "d1ce6ba9.c90f2",
757 | "x": 350,
758 | "y": 700,
759 | "wires": [
760 | [
761 | "f48c70aa.d1c998"
762 | ]
763 | ]
764 | },
765 | {
766 | "id": "f48c70aa.d1c998",
767 | "type": "switch",
768 | "z": "eaed8fa5.46ccc8",
769 | "name": "",
770 | "property": "payload",
771 | "propertyType": "msg",
772 | "rules": [
773 | {
774 | "t": "gt",
775 | "v": "50",
776 | "vt": "num"
777 | },
778 | {
779 | "t": "lt",
780 | "v": "-50",
781 | "vt": "num"
782 | },
783 | {
784 | "t": "btwn",
785 | "v": "-50",
786 | "vt": "num",
787 | "v2": "50",
788 | "v2t": "num"
789 | }
790 | ],
791 | "checkall": "true",
792 | "repair": false,
793 | "outputs": 3,
794 | "x": 670,
795 | "y": 700,
796 | "wires": [
797 | [
798 | "ee1dbad1.0a15d"
799 | ],
800 | [
801 | "5d72c5a8.79d204"
802 | ],
803 | [
804 | "7031411.60caec"
805 | ]
806 | ]
807 | },
808 | {
809 | "id": "ee1dbad1.0a15d",
810 | "type": "change",
811 | "z": "eaed8fa5.46ccc8",
812 | "name": "",
813 | "rules": [
814 | {
815 | "t": "set",
816 | "p": "payload",
817 | "pt": "msg",
818 | "to": "Right side up",
819 | "tot": "str"
820 | }
821 | ],
822 | "action": "",
823 | "property": "",
824 | "from": "",
825 | "to": "",
826 | "reg": false,
827 | "x": 930,
828 | "y": 640,
829 | "wires": [
830 | [
831 | "d7fd4e74.22752"
832 | ]
833 | ]
834 | },
835 | {
836 | "id": "5d72c5a8.79d204",
837 | "type": "change",
838 | "z": "eaed8fa5.46ccc8",
839 | "name": "",
840 | "rules": [
841 | {
842 | "t": "set",
843 | "p": "payload",
844 | "pt": "msg",
845 | "to": "Upside down",
846 | "tot": "str"
847 | }
848 | ],
849 | "action": "",
850 | "property": "",
851 | "from": "",
852 | "to": "",
853 | "reg": false,
854 | "x": 930,
855 | "y": 700,
856 | "wires": [
857 | [
858 | "d7fd4e74.22752"
859 | ]
860 | ]
861 | },
862 | {
863 | "id": "7031411.60caec",
864 | "type": "change",
865 | "z": "eaed8fa5.46ccc8",
866 | "name": "",
867 | "rules": [
868 | {
869 | "t": "set",
870 | "p": "payload",
871 | "pt": "msg",
872 | "to": "On its side",
873 | "tot": "str"
874 | }
875 | ],
876 | "action": "",
877 | "property": "",
878 | "from": "",
879 | "to": "",
880 | "reg": false,
881 | "x": 930,
882 | "y": 760,
883 | "wires": [
884 | [
885 | "d7fd4e74.22752"
886 | ]
887 | ]
888 | },
889 | {
890 | "id": "d7fd4e74.22752",
891 | "type": "ui_text",
892 | "z": "eaed8fa5.46ccc8",
893 | "group": "7e2d42c6.4b1d84",
894 | "order": 2,
895 | "width": 0,
896 | "height": 0,
897 | "name": "",
898 | "label": "Orientation",
899 | "format": "{{msg.payload}}",
900 | "layout": "row-spread",
901 | "x": 1220,
902 | "y": 700,
903 | "wires": []
904 | },
905 | {
906 | "id": "ddc35c81.3d6f5",
907 | "type": "mqtt in",
908 | "z": "eaed8fa5.46ccc8",
909 | "name": "",
910 | "topic": "bt-mqtt-gateway/ruuvitag/tag1/pressure",
911 | "qos": "2",
912 | "datatype": "auto",
913 | "broker": "d1ce6ba9.c90f2",
914 | "x": 330,
915 | "y": 160,
916 | "wires": [
917 | [
918 | "83769d57.833558"
919 | ]
920 | ]
921 | },
922 | {
923 | "id": "83769d57.833558",
924 | "type": "ui_gauge",
925 | "z": "eaed8fa5.46ccc8",
926 | "name": "RuuviTag 1 pressure",
927 | "group": "4f008f1d.e39768",
928 | "order": 0,
929 | "width": 0,
930 | "height": 0,
931 | "gtype": "gage",
932 | "title": "Pressure",
933 | "label": "hPa",
934 | "format": "{{value}}",
935 | "min": "300",
936 | "max": "1100",
937 | "colors": [
938 | "#00b500",
939 | "#e6e600",
940 | "#ca3838"
941 | ],
942 | "seg1": "",
943 | "seg2": "",
944 | "x": 900,
945 | "y": 160,
946 | "wires": []
947 | },
948 | {
949 | "id": "9aeaf7b.0047188",
950 | "type": "mqtt in",
951 | "z": "eaed8fa5.46ccc8",
952 | "name": "",
953 | "topic": "bt-mqtt-gateway/ruuvitag/tag2/pressure",
954 | "qos": "2",
955 | "datatype": "auto",
956 | "broker": "d1ce6ba9.c90f2",
957 | "x": 330,
958 | "y": 560,
959 | "wires": [
960 | [
961 | "904d0c9b.8cb66"
962 | ]
963 | ]
964 | },
965 | {
966 | "id": "904d0c9b.8cb66",
967 | "type": "ui_gauge",
968 | "z": "eaed8fa5.46ccc8",
969 | "name": "RuuviTag 2 pressure",
970 | "group": "7e2d42c6.4b1d84",
971 | "order": 0,
972 | "width": 0,
973 | "height": 0,
974 | "gtype": "gage",
975 | "title": "Pressure",
976 | "label": "hPa",
977 | "format": "{{value}}",
978 | "min": "300",
979 | "max": "1100",
980 | "colors": [
981 | "#00b500",
982 | "#e6e600",
983 | "#ca3838"
984 | ],
985 | "seg1": "",
986 | "seg2": "",
987 | "x": 920,
988 | "y": 560,
989 | "wires": []
990 | },
991 | {
992 | "id": "6c5a860d.edc83",
993 | "type": "mqtt in",
994 | "z": "eaed8fa5.46ccc8",
995 | "name": "",
996 | "topic": "bt-mqtt-gateway/ruuvitag/tag3/pressure",
997 | "qos": "2",
998 | "datatype": "auto",
999 | "broker": "d1ce6ba9.c90f2",
1000 | "x": 330,
1001 | "y": 1020,
1002 | "wires": [
1003 | [
1004 | "af08bcda.b4f22"
1005 | ]
1006 | ]
1007 | },
1008 | {
1009 | "id": "af08bcda.b4f22",
1010 | "type": "ui_gauge",
1011 | "z": "eaed8fa5.46ccc8",
1012 | "name": "RuuviTag 3 pressure",
1013 | "group": "c13387c.ae43bf8",
1014 | "order": 0,
1015 | "width": 0,
1016 | "height": 0,
1017 | "gtype": "gage",
1018 | "title": "Pressure",
1019 | "label": "hPa",
1020 | "format": "{{value}}",
1021 | "min": "300",
1022 | "max": "1100",
1023 | "colors": [
1024 | "#00b500",
1025 | "#e6e600",
1026 | "#ca3838"
1027 | ],
1028 | "seg1": "",
1029 | "seg2": "",
1030 | "x": 920,
1031 | "y": 1020,
1032 | "wires": []
1033 | },
1034 | {
1035 | "id": "b51ce146.ddb3f",
1036 | "type": "mqtt in",
1037 | "z": "eaed8fa5.46ccc8",
1038 | "name": "",
1039 | "topic": "bt-mqtt-gateway/ruuvitag/tag4/temperature",
1040 | "qos": "2",
1041 | "datatype": "auto",
1042 | "broker": "d1ce6ba9.c90f2",
1043 | "x": 350,
1044 | "y": 1320,
1045 | "wires": [
1046 | [
1047 | "bb064d50.922058"
1048 | ]
1049 | ]
1050 | },
1051 | {
1052 | "id": "bb064d50.922058",
1053 | "type": "ui_gauge",
1054 | "z": "eaed8fa5.46ccc8",
1055 | "name": "RuuviTag 4 temperature",
1056 | "group": "30b8e062.37b95",
1057 | "order": 0,
1058 | "width": 0,
1059 | "height": 0,
1060 | "gtype": "gage",
1061 | "title": "Temperature",
1062 | "label": "\u00b0C",
1063 | "format": "{{value}}",
1064 | "min": "-40",
1065 | "max": "85",
1066 | "colors": [
1067 | "#00b500",
1068 | "#e6e600",
1069 | "#ca3838"
1070 | ],
1071 | "seg1": "",
1072 | "seg2": "",
1073 | "x": 930,
1074 | "y": 1320,
1075 | "wires": []
1076 | },
1077 | {
1078 | "id": "e788725d.5a66a8",
1079 | "type": "mqtt in",
1080 | "z": "eaed8fa5.46ccc8",
1081 | "name": "",
1082 | "topic": "bt-mqtt-gateway/ruuvitag/tag4/humidity",
1083 | "qos": "2",
1084 | "datatype": "auto",
1085 | "broker": "d1ce6ba9.c90f2",
1086 | "x": 330,
1087 | "y": 1380,
1088 | "wires": [
1089 | [
1090 | "b486c770.b4c848"
1091 | ]
1092 | ]
1093 | },
1094 | {
1095 | "id": "b486c770.b4c848",
1096 | "type": "ui_gauge",
1097 | "z": "eaed8fa5.46ccc8",
1098 | "name": "RuuviTag 4 humidity",
1099 | "group": "30b8e062.37b95",
1100 | "order": 0,
1101 | "width": 0,
1102 | "height": 0,
1103 | "gtype": "gage",
1104 | "title": "Humidity",
1105 | "label": "%",
1106 | "format": "{{value}}",
1107 | "min": 0,
1108 | "max": "100",
1109 | "colors": [
1110 | "#00b500",
1111 | "#e6e600",
1112 | "#ca3838"
1113 | ],
1114 | "seg1": "",
1115 | "seg2": "",
1116 | "x": 920,
1117 | "y": 1380,
1118 | "wires": []
1119 | },
1120 | {
1121 | "id": "37a091af.b60cbe",
1122 | "type": "mqtt in",
1123 | "z": "eaed8fa5.46ccc8",
1124 | "name": "",
1125 | "topic": "bt-mqtt-gateway/ruuvitag/tag4/acceleration_z",
1126 | "qos": "2",
1127 | "datatype": "auto",
1128 | "broker": "d1ce6ba9.c90f2",
1129 | "x": 350,
1130 | "y": 1580,
1131 | "wires": [
1132 | [
1133 | "59b69629.903d6"
1134 | ]
1135 | ]
1136 | },
1137 | {
1138 | "id": "59b69629.903d6",
1139 | "type": "switch",
1140 | "z": "eaed8fa5.46ccc8",
1141 | "name": "",
1142 | "property": "payload",
1143 | "propertyType": "msg",
1144 | "rules": [
1145 | {
1146 | "t": "gt",
1147 | "v": "50",
1148 | "vt": "num"
1149 | },
1150 | {
1151 | "t": "lt",
1152 | "v": "-50",
1153 | "vt": "num"
1154 | },
1155 | {
1156 | "t": "btwn",
1157 | "v": "-50",
1158 | "vt": "num",
1159 | "v2": "50",
1160 | "v2t": "num"
1161 | }
1162 | ],
1163 | "checkall": "true",
1164 | "repair": false,
1165 | "outputs": 3,
1166 | "x": 670,
1167 | "y": 1580,
1168 | "wires": [
1169 | [
1170 | "cb8a25b6.0233a"
1171 | ],
1172 | [
1173 | "73a39f82.39aab8"
1174 | ],
1175 | [
1176 | "c4599fee.99bf18"
1177 | ]
1178 | ]
1179 | },
1180 | {
1181 | "id": "cb8a25b6.0233a",
1182 | "type": "change",
1183 | "z": "eaed8fa5.46ccc8",
1184 | "name": "",
1185 | "rules": [
1186 | {
1187 | "t": "set",
1188 | "p": "payload",
1189 | "pt": "msg",
1190 | "to": "Right side up",
1191 | "tot": "str"
1192 | }
1193 | ],
1194 | "action": "",
1195 | "property": "",
1196 | "from": "",
1197 | "to": "",
1198 | "reg": false,
1199 | "x": 930,
1200 | "y": 1520,
1201 | "wires": [
1202 | [
1203 | "10ec976c.4b2d19"
1204 | ]
1205 | ]
1206 | },
1207 | {
1208 | "id": "73a39f82.39aab8",
1209 | "type": "change",
1210 | "z": "eaed8fa5.46ccc8",
1211 | "name": "",
1212 | "rules": [
1213 | {
1214 | "t": "set",
1215 | "p": "payload",
1216 | "pt": "msg",
1217 | "to": "Upside down",
1218 | "tot": "str"
1219 | }
1220 | ],
1221 | "action": "",
1222 | "property": "",
1223 | "from": "",
1224 | "to": "",
1225 | "reg": false,
1226 | "x": 930,
1227 | "y": 1580,
1228 | "wires": [
1229 | [
1230 | "10ec976c.4b2d19"
1231 | ]
1232 | ]
1233 | },
1234 | {
1235 | "id": "c4599fee.99bf18",
1236 | "type": "change",
1237 | "z": "eaed8fa5.46ccc8",
1238 | "name": "",
1239 | "rules": [
1240 | {
1241 | "t": "set",
1242 | "p": "payload",
1243 | "pt": "msg",
1244 | "to": "On its side",
1245 | "tot": "str"
1246 | }
1247 | ],
1248 | "action": "",
1249 | "property": "",
1250 | "from": "",
1251 | "to": "",
1252 | "reg": false,
1253 | "x": 930,
1254 | "y": 1640,
1255 | "wires": [
1256 | [
1257 | "10ec976c.4b2d19"
1258 | ]
1259 | ]
1260 | },
1261 | {
1262 | "id": "10ec976c.4b2d19",
1263 | "type": "ui_text",
1264 | "z": "eaed8fa5.46ccc8",
1265 | "group": "30b8e062.37b95",
1266 | "order": 2,
1267 | "width": 0,
1268 | "height": 0,
1269 | "name": "",
1270 | "label": "Orientation",
1271 | "format": "{{msg.payload}}",
1272 | "layout": "row-spread",
1273 | "x": 1220,
1274 | "y": 1580,
1275 | "wires": []
1276 | },
1277 | {
1278 | "id": "78eab4ae.36b62c",
1279 | "type": "mqtt in",
1280 | "z": "eaed8fa5.46ccc8",
1281 | "name": "",
1282 | "topic": "bt-mqtt-gateway/ruuvitag/tag4/pressure",
1283 | "qos": "2",
1284 | "datatype": "auto",
1285 | "broker": "d1ce6ba9.c90f2",
1286 | "x": 330,
1287 | "y": 1460,
1288 | "wires": [
1289 | [
1290 | "13f812ff.c0fb35"
1291 | ]
1292 | ]
1293 | },
1294 | {
1295 | "id": "13f812ff.c0fb35",
1296 | "type": "ui_gauge",
1297 | "z": "eaed8fa5.46ccc8",
1298 | "name": "RuuviTag 4 pressure",
1299 | "group": "30b8e062.37b95",
1300 | "order": 0,
1301 | "width": 0,
1302 | "height": 0,
1303 | "gtype": "gage",
1304 | "title": "Pressure",
1305 | "label": "hPa",
1306 | "format": "{{value}}",
1307 | "min": "300",
1308 | "max": "1100",
1309 | "colors": [
1310 | "#00b500",
1311 | "#e6e600",
1312 | "#ca3838"
1313 | ],
1314 | "seg1": "",
1315 | "seg2": "",
1316 | "x": 920,
1317 | "y": 1460,
1318 | "wires": []
1319 | }
1320 | ]
1321 |
--------------------------------------------------------------------------------
/grafana/dashboards/ruuvitag.json:
--------------------------------------------------------------------------------
1 | {
2 | "annotations": {
3 | "list": [
4 | {
5 | "builtIn": 1,
6 | "datasource": "-- Grafana --",
7 | "enable": true,
8 | "hide": true,
9 | "iconColor": "rgba(0, 211, 255, 1)",
10 | "name": "Annotations & Alerts",
11 | "type": "dashboard"
12 | }
13 | ]
14 | },
15 | "editable": true,
16 | "gnetId": null,
17 | "graphTooltip": 0,
18 | "links": [],
19 | "panels": [
20 | {
21 | "aliasColors": {},
22 | "bars": false,
23 | "dashLength": 10,
24 | "dashes": false,
25 | "datasource": "InfluxDB",
26 | "fill": 1,
27 | "fillGradient": 0,
28 | "gridPos": {
29 | "h": 8,
30 | "w": 12,
31 | "x": 0,
32 | "y": 0
33 | },
34 | "hiddenSeries": false,
35 | "id": 2,
36 | "legend": {
37 | "avg": false,
38 | "current": false,
39 | "max": false,
40 | "min": false,
41 | "show": true,
42 | "total": false,
43 | "values": false
44 | },
45 | "lines": true,
46 | "linewidth": 1,
47 | "nullPointMode": "null",
48 | "options": {
49 | "dataLinks": []
50 | },
51 | "percentage": false,
52 | "pointradius": 2,
53 | "points": false,
54 | "renderer": "flot",
55 | "seriesOverrides": [],
56 | "spaceLength": 10,
57 | "stack": false,
58 | "steppedLine": false,
59 | "targets": [
60 | {
61 | "alias": "RuuviTag 1",
62 | "groupBy": [
63 | {
64 | "params": [
65 | "$__interval"
66 | ],
67 | "type": "time"
68 | },
69 | {
70 | "params": [
71 | "null"
72 | ],
73 | "type": "fill"
74 | }
75 | ],
76 | "measurement": "ruuvitag",
77 | "orderByTime": "ASC",
78 | "policy": "default",
79 | "refId": "A",
80 | "resultFormat": "time_series",
81 | "select": [
82 | [
83 | {
84 | "params": [
85 | "value"
86 | ],
87 | "type": "field"
88 | },
89 | {
90 | "params": [],
91 | "type": "mean"
92 | }
93 | ]
94 | ],
95 | "tags": [
96 | {
97 | "key": "topic",
98 | "operator": "=",
99 | "value": "bt-mqtt-gateway/ruuvitag/tag1/temperature"
100 | }
101 | ]
102 | },
103 | {
104 | "alias": "RuuviTag 2",
105 | "groupBy": [
106 | {
107 | "params": [
108 | "$__interval"
109 | ],
110 | "type": "time"
111 | },
112 | {
113 | "params": [
114 | "null"
115 | ],
116 | "type": "fill"
117 | }
118 | ],
119 | "measurement": "ruuvitag",
120 | "orderByTime": "ASC",
121 | "policy": "default",
122 | "refId": "B",
123 | "resultFormat": "time_series",
124 | "select": [
125 | [
126 | {
127 | "params": [
128 | "value"
129 | ],
130 | "type": "field"
131 | },
132 | {
133 | "params": [],
134 | "type": "mean"
135 | }
136 | ]
137 | ],
138 | "tags": [
139 | {
140 | "key": "topic",
141 | "operator": "=",
142 | "value": "bt-mqtt-gateway/ruuvitag/tag2/temperature"
143 | }
144 | ]
145 | },
146 | {
147 | "alias": "RuuviTag 3",
148 | "groupBy": [
149 | {
150 | "params": [
151 | "$__interval"
152 | ],
153 | "type": "time"
154 | },
155 | {
156 | "params": [
157 | "null"
158 | ],
159 | "type": "fill"
160 | }
161 | ],
162 | "measurement": "ruuvitag",
163 | "orderByTime": "ASC",
164 | "policy": "default",
165 | "refId": "C",
166 | "resultFormat": "time_series",
167 | "select": [
168 | [
169 | {
170 | "params": [
171 | "value"
172 | ],
173 | "type": "field"
174 | },
175 | {
176 | "params": [],
177 | "type": "mean"
178 | }
179 | ]
180 | ],
181 | "tags": [
182 | {
183 | "key": "topic",
184 | "operator": "=",
185 | "value": "bt-mqtt-gateway/ruuvitag/tag3/temperature"
186 | }
187 | ]
188 | }
189 | ],
190 | "thresholds": [],
191 | "timeFrom": null,
192 | "timeRegions": [],
193 | "timeShift": null,
194 | "title": "Temperature",
195 | "tooltip": {
196 | "shared": true,
197 | "sort": 0,
198 | "value_type": "individual"
199 | },
200 | "type": "graph",
201 | "xaxis": {
202 | "buckets": null,
203 | "mode": "time",
204 | "name": null,
205 | "show": true,
206 | "values": []
207 | },
208 | "yaxes": [
209 | {
210 | "format": "celsius",
211 | "label": null,
212 | "logBase": 1,
213 | "max": null,
214 | "min": null,
215 | "show": true
216 | },
217 | {
218 | "format": "short",
219 | "label": null,
220 | "logBase": 1,
221 | "max": null,
222 | "min": null,
223 | "show": true
224 | }
225 | ],
226 | "yaxis": {
227 | "align": false,
228 | "alignLevel": null
229 | }
230 | },
231 | {
232 | "aliasColors": {},
233 | "bars": false,
234 | "dashLength": 10,
235 | "dashes": false,
236 | "datasource": "InfluxDB",
237 | "fill": 1,
238 | "fillGradient": 0,
239 | "gridPos": {
240 | "h": 8,
241 | "w": 12,
242 | "x": 12,
243 | "y": 0
244 | },
245 | "hiddenSeries": false,
246 | "id": 4,
247 | "legend": {
248 | "avg": false,
249 | "current": false,
250 | "max": false,
251 | "min": false,
252 | "show": true,
253 | "total": false,
254 | "values": false
255 | },
256 | "lines": true,
257 | "linewidth": 1,
258 | "nullPointMode": "null",
259 | "options": {
260 | "dataLinks": []
261 | },
262 | "percentage": false,
263 | "pointradius": 2,
264 | "points": false,
265 | "renderer": "flot",
266 | "seriesOverrides": [],
267 | "spaceLength": 10,
268 | "stack": false,
269 | "steppedLine": false,
270 | "targets": [
271 | {
272 | "alias": "RuuviTag 1",
273 | "groupBy": [
274 | {
275 | "params": [
276 | "$__interval"
277 | ],
278 | "type": "time"
279 | },
280 | {
281 | "params": [
282 | "null"
283 | ],
284 | "type": "fill"
285 | }
286 | ],
287 | "measurement": "ruuvitag",
288 | "orderByTime": "ASC",
289 | "policy": "default",
290 | "refId": "A",
291 | "resultFormat": "time_series",
292 | "select": [
293 | [
294 | {
295 | "params": [
296 | "value"
297 | ],
298 | "type": "field"
299 | },
300 | {
301 | "params": [],
302 | "type": "mean"
303 | }
304 | ]
305 | ],
306 | "tags": [
307 | {
308 | "key": "topic",
309 | "operator": "=",
310 | "value": "bt-mqtt-gateway/ruuvitag/tag1/humidity"
311 | }
312 | ]
313 | },
314 | {
315 | "alias": "RuuviTag 2",
316 | "groupBy": [
317 | {
318 | "params": [
319 | "$__interval"
320 | ],
321 | "type": "time"
322 | },
323 | {
324 | "params": [
325 | "null"
326 | ],
327 | "type": "fill"
328 | }
329 | ],
330 | "measurement": "ruuvitag",
331 | "orderByTime": "ASC",
332 | "policy": "default",
333 | "refId": "B",
334 | "resultFormat": "time_series",
335 | "select": [
336 | [
337 | {
338 | "params": [
339 | "value"
340 | ],
341 | "type": "field"
342 | },
343 | {
344 | "params": [],
345 | "type": "mean"
346 | }
347 | ]
348 | ],
349 | "tags": [
350 | {
351 | "key": "topic",
352 | "operator": "=",
353 | "value": "bt-mqtt-gateway/ruuvitag/tag2/humidity"
354 | }
355 | ]
356 | },
357 | {
358 | "alias": "RuuviTag 3",
359 | "groupBy": [
360 | {
361 | "params": [
362 | "$__interval"
363 | ],
364 | "type": "time"
365 | },
366 | {
367 | "params": [
368 | "null"
369 | ],
370 | "type": "fill"
371 | }
372 | ],
373 | "measurement": "ruuvitag",
374 | "orderByTime": "ASC",
375 | "policy": "default",
376 | "refId": "C",
377 | "resultFormat": "time_series",
378 | "select": [
379 | [
380 | {
381 | "params": [
382 | "value"
383 | ],
384 | "type": "field"
385 | },
386 | {
387 | "params": [],
388 | "type": "mean"
389 | }
390 | ]
391 | ],
392 | "tags": [
393 | {
394 | "key": "topic",
395 | "operator": "=",
396 | "value": "bt-mqtt-gateway/ruuvitag/tag3/humidity"
397 | }
398 | ]
399 | }
400 | ],
401 | "thresholds": [],
402 | "timeFrom": null,
403 | "timeRegions": [],
404 | "timeShift": null,
405 | "title": "Humidity",
406 | "tooltip": {
407 | "shared": true,
408 | "sort": 0,
409 | "value_type": "individual"
410 | },
411 | "type": "graph",
412 | "xaxis": {
413 | "buckets": null,
414 | "mode": "time",
415 | "name": null,
416 | "show": true,
417 | "values": []
418 | },
419 | "yaxes": [
420 | {
421 | "format": "humidity",
422 | "label": null,
423 | "logBase": 1,
424 | "max": null,
425 | "min": null,
426 | "show": true
427 | },
428 | {
429 | "format": "short",
430 | "label": null,
431 | "logBase": 1,
432 | "max": null,
433 | "min": null,
434 | "show": true
435 | }
436 | ],
437 | "yaxis": {
438 | "align": false,
439 | "alignLevel": null
440 | }
441 | },
442 | {
443 | "cacheTimeout": null,
444 | "datasource": null,
445 | "gridPos": {
446 | "h": 5,
447 | "w": 3,
448 | "x": 0,
449 | "y": 8
450 | },
451 | "id": 6,
452 | "links": [],
453 | "options": {
454 | "fieldOptions": {
455 | "calcs": [
456 | "lastNotNull"
457 | ],
458 | "defaults": {
459 | "decimals": 1,
460 | "mappings": [
461 | {
462 | "id": 0,
463 | "op": "=",
464 | "text": "N/A",
465 | "type": 1,
466 | "value": "null"
467 | }
468 | ],
469 | "max": 85,
470 | "min": -40,
471 | "nullValueMode": "connected",
472 | "thresholds": [
473 | {
474 | "color": "green",
475 | "value": null
476 | },
477 | {
478 | "color": "red",
479 | "value": 80
480 | }
481 | ],
482 | "unit": "celsius"
483 | },
484 | "override": {},
485 | "values": false
486 | },
487 | "orientation": "horizontal",
488 | "showThresholdLabels": false,
489 | "showThresholdMarkers": true
490 | },
491 | "pluginVersion": "6.5.0-pre",
492 | "targets": [
493 | {
494 | "groupBy": [
495 | {
496 | "params": [
497 | "$__interval"
498 | ],
499 | "type": "time"
500 | },
501 | {
502 | "params": [
503 | "null"
504 | ],
505 | "type": "fill"
506 | }
507 | ],
508 | "measurement": "ruuvitag",
509 | "orderByTime": "ASC",
510 | "policy": "default",
511 | "refId": "A",
512 | "resultFormat": "time_series",
513 | "select": [
514 | [
515 | {
516 | "params": [
517 | "value"
518 | ],
519 | "type": "field"
520 | },
521 | {
522 | "params": [],
523 | "type": "mean"
524 | }
525 | ]
526 | ],
527 | "tags": [
528 | {
529 | "key": "topic",
530 | "operator": "=",
531 | "value": "bt-mqtt-gateway/ruuvitag/tag1/temperature"
532 | }
533 | ]
534 | }
535 | ],
536 | "timeFrom": null,
537 | "timeShift": null,
538 | "title": "Temperature 1",
539 | "type": "gauge"
540 | },
541 | {
542 | "datasource": null,
543 | "gridPos": {
544 | "h": 5,
545 | "w": 3,
546 | "x": 3,
547 | "y": 8
548 | },
549 | "id": 8,
550 | "options": {
551 | "fieldOptions": {
552 | "calcs": [
553 | "lastNotNull"
554 | ],
555 | "defaults": {
556 | "decimals": 1,
557 | "mappings": [],
558 | "max": 85,
559 | "min": -40,
560 | "thresholds": [
561 | {
562 | "color": "green",
563 | "value": null
564 | },
565 | {
566 | "color": "red",
567 | "value": 80
568 | }
569 | ],
570 | "unit": "celsius"
571 | },
572 | "override": {},
573 | "values": false
574 | },
575 | "orientation": "auto",
576 | "showThresholdLabels": false,
577 | "showThresholdMarkers": true
578 | },
579 | "pluginVersion": "6.5.0-pre",
580 | "targets": [
581 | {
582 | "groupBy": [
583 | {
584 | "params": [
585 | "$__interval"
586 | ],
587 | "type": "time"
588 | },
589 | {
590 | "params": [
591 | "null"
592 | ],
593 | "type": "fill"
594 | }
595 | ],
596 | "measurement": "ruuvitag",
597 | "orderByTime": "ASC",
598 | "policy": "default",
599 | "refId": "A",
600 | "resultFormat": "time_series",
601 | "select": [
602 | [
603 | {
604 | "params": [
605 | "value"
606 | ],
607 | "type": "field"
608 | },
609 | {
610 | "params": [],
611 | "type": "mean"
612 | }
613 | ]
614 | ],
615 | "tags": [
616 | {
617 | "key": "topic",
618 | "operator": "=",
619 | "value": "bt-mqtt-gateway/ruuvitag/tag2/temperature"
620 | }
621 | ]
622 | }
623 | ],
624 | "timeFrom": null,
625 | "timeShift": null,
626 | "title": "Temperature 2",
627 | "type": "gauge"
628 | },
629 | {
630 | "datasource": null,
631 | "gridPos": {
632 | "h": 5,
633 | "w": 3,
634 | "x": 6,
635 | "y": 8
636 | },
637 | "id": 10,
638 | "options": {
639 | "fieldOptions": {
640 | "calcs": [
641 | "lastNotNull"
642 | ],
643 | "defaults": {
644 | "decimals": 1,
645 | "mappings": [],
646 | "max": 85,
647 | "min": -40,
648 | "thresholds": [
649 | {
650 | "color": "green",
651 | "value": null
652 | },
653 | {
654 | "color": "red",
655 | "value": 80
656 | }
657 | ],
658 | "unit": "celsius"
659 | },
660 | "override": {},
661 | "values": false
662 | },
663 | "orientation": "auto",
664 | "showThresholdLabels": false,
665 | "showThresholdMarkers": true
666 | },
667 | "pluginVersion": "6.5.0-pre",
668 | "targets": [
669 | {
670 | "groupBy": [
671 | {
672 | "params": [
673 | "$__interval"
674 | ],
675 | "type": "time"
676 | },
677 | {
678 | "params": [
679 | "null"
680 | ],
681 | "type": "fill"
682 | }
683 | ],
684 | "measurement": "ruuvitag",
685 | "orderByTime": "ASC",
686 | "policy": "default",
687 | "refId": "A",
688 | "resultFormat": "time_series",
689 | "select": [
690 | [
691 | {
692 | "params": [
693 | "value"
694 | ],
695 | "type": "field"
696 | },
697 | {
698 | "params": [],
699 | "type": "mean"
700 | }
701 | ]
702 | ],
703 | "tags": [
704 | {
705 | "key": "topic",
706 | "operator": "=",
707 | "value": "bt-mqtt-gateway/ruuvitag/tag3/temperature"
708 | }
709 | ]
710 | }
711 | ],
712 | "timeFrom": null,
713 | "timeShift": null,
714 | "title": "Temperature 3",
715 | "type": "gauge"
716 | },
717 | {
718 | "cacheTimeout": null,
719 | "datasource": null,
720 | "gridPos": {
721 | "h": 5,
722 | "w": 3,
723 | "x": 9,
724 | "y": 8
725 | },
726 | "id": 11,
727 | "links": [],
728 | "options": {
729 | "fieldOptions": {
730 | "calcs": [
731 | "lastNotNull"
732 | ],
733 | "defaults": {
734 | "decimals": 1,
735 | "mappings": [
736 | {
737 | "id": 0,
738 | "op": "=",
739 | "text": "N/A",
740 | "type": 1,
741 | "value": "null"
742 | }
743 | ],
744 | "max": 85,
745 | "min": -40,
746 | "nullValueMode": "connected",
747 | "thresholds": [
748 | {
749 | "color": "green",
750 | "value": null
751 | },
752 | {
753 | "color": "red",
754 | "value": 80
755 | }
756 | ],
757 | "unit": "celsius"
758 | },
759 | "override": {},
760 | "values": false
761 | },
762 | "orientation": "horizontal",
763 | "showThresholdLabels": false,
764 | "showThresholdMarkers": true
765 | },
766 | "pluginVersion": "6.5.0-pre",
767 | "targets": [
768 | {
769 | "groupBy": [
770 | {
771 | "params": [
772 | "$__interval"
773 | ],
774 | "type": "time"
775 | },
776 | {
777 | "params": [
778 | "null"
779 | ],
780 | "type": "fill"
781 | }
782 | ],
783 | "measurement": "ruuvitag",
784 | "orderByTime": "ASC",
785 | "policy": "default",
786 | "refId": "A",
787 | "resultFormat": "time_series",
788 | "select": [
789 | [
790 | {
791 | "params": [
792 | "value"
793 | ],
794 | "type": "field"
795 | },
796 | {
797 | "params": [],
798 | "type": "mean"
799 | }
800 | ]
801 | ],
802 | "tags": [
803 | {
804 | "key": "topic",
805 | "operator": "=",
806 | "value": "bt-mqtt-gateway/ruuvitag/tag4/temperature"
807 | }
808 | ]
809 | }
810 | ],
811 | "timeFrom": null,
812 | "timeShift": null,
813 | "title": "Temperature 4",
814 | "type": "gauge"
815 | },
816 | {
817 | "cacheTimeout": null,
818 | "datasource": null,
819 | "gridPos": {
820 | "h": 5,
821 | "w": 3,
822 | "x": 12,
823 | "y": 8
824 | },
825 | "id": 12,
826 | "links": [],
827 | "options": {
828 | "fieldOptions": {
829 | "calcs": [
830 | "lastNotNull"
831 | ],
832 | "defaults": {
833 | "decimals": 1,
834 | "mappings": [
835 | {
836 | "id": 0,
837 | "op": "=",
838 | "text": "N/A",
839 | "type": 1,
840 | "value": "null"
841 | }
842 | ],
843 | "max": 100,
844 | "min": 0,
845 | "nullValueMode": "connected",
846 | "thresholds": [
847 | {
848 | "color": "green",
849 | "value": null
850 | },
851 | {
852 | "color": "red",
853 | "value": 80
854 | }
855 | ],
856 | "unit": "humidity"
857 | },
858 | "override": {},
859 | "values": false
860 | },
861 | "orientation": "horizontal",
862 | "showThresholdLabels": false,
863 | "showThresholdMarkers": true
864 | },
865 | "pluginVersion": "6.5.0-pre",
866 | "targets": [
867 | {
868 | "groupBy": [
869 | {
870 | "params": [
871 | "$__interval"
872 | ],
873 | "type": "time"
874 | },
875 | {
876 | "params": [
877 | "null"
878 | ],
879 | "type": "fill"
880 | }
881 | ],
882 | "measurement": "ruuvitag",
883 | "orderByTime": "ASC",
884 | "policy": "default",
885 | "refId": "A",
886 | "resultFormat": "time_series",
887 | "select": [
888 | [
889 | {
890 | "params": [
891 | "value"
892 | ],
893 | "type": "field"
894 | },
895 | {
896 | "params": [],
897 | "type": "mean"
898 | }
899 | ]
900 | ],
901 | "tags": [
902 | {
903 | "key": "topic",
904 | "operator": "=",
905 | "value": "bt-mqtt-gateway/ruuvitag/tag1/humidity"
906 | }
907 | ]
908 | }
909 | ],
910 | "timeFrom": null,
911 | "timeShift": null,
912 | "title": "Humidity 1",
913 | "type": "gauge"
914 | },
915 | {
916 | "cacheTimeout": null,
917 | "datasource": null,
918 | "gridPos": {
919 | "h": 5,
920 | "w": 3,
921 | "x": 15,
922 | "y": 8
923 | },
924 | "id": 13,
925 | "links": [],
926 | "options": {
927 | "fieldOptions": {
928 | "calcs": [
929 | "lastNotNull"
930 | ],
931 | "defaults": {
932 | "decimals": 1,
933 | "mappings": [
934 | {
935 | "id": 0,
936 | "op": "=",
937 | "text": "N/A",
938 | "type": 1,
939 | "value": "null"
940 | }
941 | ],
942 | "max": 100,
943 | "min": 0,
944 | "nullValueMode": "connected",
945 | "thresholds": [
946 | {
947 | "color": "green",
948 | "value": null
949 | },
950 | {
951 | "color": "red",
952 | "value": 80
953 | }
954 | ],
955 | "unit": "humidity"
956 | },
957 | "override": {},
958 | "values": false
959 | },
960 | "orientation": "horizontal",
961 | "showThresholdLabels": false,
962 | "showThresholdMarkers": true
963 | },
964 | "pluginVersion": "6.5.0-pre",
965 | "targets": [
966 | {
967 | "groupBy": [
968 | {
969 | "params": [
970 | "$__interval"
971 | ],
972 | "type": "time"
973 | },
974 | {
975 | "params": [
976 | "null"
977 | ],
978 | "type": "fill"
979 | }
980 | ],
981 | "measurement": "ruuvitag",
982 | "orderByTime": "ASC",
983 | "policy": "default",
984 | "refId": "A",
985 | "resultFormat": "time_series",
986 | "select": [
987 | [
988 | {
989 | "params": [
990 | "value"
991 | ],
992 | "type": "field"
993 | },
994 | {
995 | "params": [],
996 | "type": "mean"
997 | }
998 | ]
999 | ],
1000 | "tags": [
1001 | {
1002 | "key": "topic",
1003 | "operator": "=",
1004 | "value": "bt-mqtt-gateway/ruuvitag/tag2/humidity"
1005 | }
1006 | ]
1007 | }
1008 | ],
1009 | "timeFrom": null,
1010 | "timeShift": null,
1011 | "title": "Humidity 2",
1012 | "type": "gauge"
1013 | },
1014 | {
1015 | "cacheTimeout": null,
1016 | "datasource": null,
1017 | "gridPos": {
1018 | "h": 5,
1019 | "w": 3,
1020 | "x": 18,
1021 | "y": 8
1022 | },
1023 | "id": 14,
1024 | "links": [],
1025 | "options": {
1026 | "fieldOptions": {
1027 | "calcs": [
1028 | "lastNotNull"
1029 | ],
1030 | "defaults": {
1031 | "decimals": 1,
1032 | "mappings": [
1033 | {
1034 | "id": 0,
1035 | "op": "=",
1036 | "text": "N/A",
1037 | "type": 1,
1038 | "value": "null"
1039 | }
1040 | ],
1041 | "max": 100,
1042 | "min": 0,
1043 | "nullValueMode": "connected",
1044 | "thresholds": [
1045 | {
1046 | "color": "green",
1047 | "value": null
1048 | },
1049 | {
1050 | "color": "red",
1051 | "value": 80
1052 | }
1053 | ],
1054 | "unit": "humidity"
1055 | },
1056 | "override": {},
1057 | "values": false
1058 | },
1059 | "orientation": "horizontal",
1060 | "showThresholdLabels": false,
1061 | "showThresholdMarkers": true
1062 | },
1063 | "pluginVersion": "6.5.0-pre",
1064 | "targets": [
1065 | {
1066 | "groupBy": [
1067 | {
1068 | "params": [
1069 | "$__interval"
1070 | ],
1071 | "type": "time"
1072 | },
1073 | {
1074 | "params": [
1075 | "null"
1076 | ],
1077 | "type": "fill"
1078 | }
1079 | ],
1080 | "measurement": "ruuvitag",
1081 | "orderByTime": "ASC",
1082 | "policy": "default",
1083 | "refId": "A",
1084 | "resultFormat": "time_series",
1085 | "select": [
1086 | [
1087 | {
1088 | "params": [
1089 | "value"
1090 | ],
1091 | "type": "field"
1092 | },
1093 | {
1094 | "params": [],
1095 | "type": "mean"
1096 | }
1097 | ]
1098 | ],
1099 | "tags": [
1100 | {
1101 | "key": "topic",
1102 | "operator": "=",
1103 | "value": "bt-mqtt-gateway/ruuvitag/tag3/humidity"
1104 | }
1105 | ]
1106 | }
1107 | ],
1108 | "timeFrom": null,
1109 | "timeShift": null,
1110 | "title": "Humidity 3",
1111 | "type": "gauge"
1112 | },
1113 | {
1114 | "cacheTimeout": null,
1115 | "datasource": null,
1116 | "gridPos": {
1117 | "h": 5,
1118 | "w": 3,
1119 | "x": 21,
1120 | "y": 8
1121 | },
1122 | "id": 15,
1123 | "links": [],
1124 | "options": {
1125 | "fieldOptions": {
1126 | "calcs": [
1127 | "lastNotNull"
1128 | ],
1129 | "defaults": {
1130 | "decimals": 1,
1131 | "mappings": [
1132 | {
1133 | "id": 0,
1134 | "op": "=",
1135 | "text": "N/A",
1136 | "type": 1,
1137 | "value": "null"
1138 | }
1139 | ],
1140 | "max": 100,
1141 | "min": 0,
1142 | "nullValueMode": "connected",
1143 | "thresholds": [
1144 | {
1145 | "color": "green",
1146 | "value": null
1147 | },
1148 | {
1149 | "color": "red",
1150 | "value": 80
1151 | }
1152 | ],
1153 | "unit": "humidity"
1154 | },
1155 | "override": {},
1156 | "values": false
1157 | },
1158 | "orientation": "horizontal",
1159 | "showThresholdLabels": false,
1160 | "showThresholdMarkers": true
1161 | },
1162 | "pluginVersion": "6.5.0-pre",
1163 | "targets": [
1164 | {
1165 | "groupBy": [
1166 | {
1167 | "params": [
1168 | "$__interval"
1169 | ],
1170 | "type": "time"
1171 | },
1172 | {
1173 | "params": [
1174 | "null"
1175 | ],
1176 | "type": "fill"
1177 | }
1178 | ],
1179 | "measurement": "ruuvitag",
1180 | "orderByTime": "ASC",
1181 | "policy": "default",
1182 | "refId": "A",
1183 | "resultFormat": "time_series",
1184 | "select": [
1185 | [
1186 | {
1187 | "params": [
1188 | "value"
1189 | ],
1190 | "type": "field"
1191 | },
1192 | {
1193 | "params": [],
1194 | "type": "mean"
1195 | }
1196 | ]
1197 | ],
1198 | "tags": [
1199 | {
1200 | "key": "topic",
1201 | "operator": "=",
1202 | "value": "bt-mqtt-gateway/ruuvitag/tag4/humidity"
1203 | }
1204 | ]
1205 | }
1206 | ],
1207 | "timeFrom": null,
1208 | "timeShift": null,
1209 | "title": "Humidity 4",
1210 | "type": "gauge"
1211 | },
1212 | {
1213 | "cacheTimeout": null,
1214 | "datasource": null,
1215 | "gridPos": {
1216 | "h": 8,
1217 | "w": 12,
1218 | "x": 0,
1219 | "y": 13
1220 | },
1221 | "id": 17,
1222 | "links": [],
1223 | "options": {
1224 | "displayMode": "lcd",
1225 | "fieldOptions": {
1226 | "calcs": [
1227 | "lastNotNull"
1228 | ],
1229 | "defaults": {
1230 | "mappings": [],
1231 | "max": 3000,
1232 | "min": 0,
1233 | "thresholds": [
1234 | {
1235 | "color": "red",
1236 | "value": null
1237 | },
1238 | {
1239 | "color": "#EAB839",
1240 | "value": 2000
1241 | },
1242 | {
1243 | "color": "green",
1244 | "value": 2500
1245 | }
1246 | ],
1247 | "unit": "mvolt"
1248 | },
1249 | "override": {},
1250 | "values": false
1251 | },
1252 | "orientation": "horizontal"
1253 | },
1254 | "pluginVersion": "6.5.0-pre",
1255 | "targets": [
1256 | {
1257 | "alias": "RuuviTag 1",
1258 | "groupBy": [
1259 | {
1260 | "params": [
1261 | "$__interval"
1262 | ],
1263 | "type": "time"
1264 | },
1265 | {
1266 | "params": [
1267 | "null"
1268 | ],
1269 | "type": "fill"
1270 | }
1271 | ],
1272 | "measurement": "ruuvitag",
1273 | "orderByTime": "ASC",
1274 | "policy": "default",
1275 | "refId": "A",
1276 | "resultFormat": "time_series",
1277 | "select": [
1278 | [
1279 | {
1280 | "params": [
1281 | "value"
1282 | ],
1283 | "type": "field"
1284 | },
1285 | {
1286 | "params": [],
1287 | "type": "mean"
1288 | }
1289 | ]
1290 | ],
1291 | "tags": [
1292 | {
1293 | "key": "topic",
1294 | "operator": "=",
1295 | "value": "bt-mqtt-gateway/ruuvitag/tag1/battery"
1296 | }
1297 | ]
1298 | },
1299 | {
1300 | "alias": "RuuviTag 2",
1301 | "groupBy": [
1302 | {
1303 | "params": [
1304 | "$__interval"
1305 | ],
1306 | "type": "time"
1307 | },
1308 | {
1309 | "params": [
1310 | "null"
1311 | ],
1312 | "type": "fill"
1313 | }
1314 | ],
1315 | "measurement": "ruuvitag",
1316 | "orderByTime": "ASC",
1317 | "policy": "default",
1318 | "refId": "B",
1319 | "resultFormat": "time_series",
1320 | "select": [
1321 | [
1322 | {
1323 | "params": [
1324 | "value"
1325 | ],
1326 | "type": "field"
1327 | },
1328 | {
1329 | "params": [],
1330 | "type": "mean"
1331 | }
1332 | ]
1333 | ],
1334 | "tags": [
1335 | {
1336 | "key": "topic",
1337 | "operator": "=",
1338 | "value": "bt-mqtt-gateway/ruuvitag/tag2/battery"
1339 | }
1340 | ]
1341 | },
1342 | {
1343 | "alias": "RuuviTag 3",
1344 | "groupBy": [
1345 | {
1346 | "params": [
1347 | "$__interval"
1348 | ],
1349 | "type": "time"
1350 | },
1351 | {
1352 | "params": [
1353 | "null"
1354 | ],
1355 | "type": "fill"
1356 | }
1357 | ],
1358 | "measurement": "ruuvitag",
1359 | "orderByTime": "ASC",
1360 | "policy": "default",
1361 | "refId": "C",
1362 | "resultFormat": "time_series",
1363 | "select": [
1364 | [
1365 | {
1366 | "params": [
1367 | "value"
1368 | ],
1369 | "type": "field"
1370 | },
1371 | {
1372 | "params": [],
1373 | "type": "mean"
1374 | }
1375 | ]
1376 | ],
1377 | "tags": [
1378 | {
1379 | "key": "topic",
1380 | "operator": "=",
1381 | "value": "bt-mqtt-gateway/ruuvitag/tag3/battery"
1382 | }
1383 | ]
1384 | },
1385 | {
1386 | "alias": "RuuviTag 4",
1387 | "groupBy": [
1388 | {
1389 | "params": [
1390 | "$__interval"
1391 | ],
1392 | "type": "time"
1393 | },
1394 | {
1395 | "params": [
1396 | "null"
1397 | ],
1398 | "type": "fill"
1399 | }
1400 | ],
1401 | "measurement": "ruuvitag",
1402 | "orderByTime": "ASC",
1403 | "policy": "default",
1404 | "refId": "D",
1405 | "resultFormat": "time_series",
1406 | "select": [
1407 | [
1408 | {
1409 | "params": [
1410 | "value"
1411 | ],
1412 | "type": "field"
1413 | },
1414 | {
1415 | "params": [],
1416 | "type": "mean"
1417 | }
1418 | ]
1419 | ],
1420 | "tags": [
1421 | {
1422 | "key": "topic",
1423 | "operator": "=",
1424 | "value": "bt-mqtt-gateway/ruuvitag/tag4/battery"
1425 | }
1426 | ]
1427 | }
1428 | ],
1429 | "timeFrom": null,
1430 | "timeShift": null,
1431 | "title": "Battery",
1432 | "type": "bargauge"
1433 | }
1434 | ],
1435 | "refresh": false,
1436 | "schemaVersion": 20,
1437 | "style": "dark",
1438 | "tags": [],
1439 | "templating": {
1440 | "list": []
1441 | },
1442 | "time": {
1443 | "from": "now-6h",
1444 | "to": "now"
1445 | },
1446 | "timepicker": {
1447 | "refresh_intervals": [
1448 | "5s",
1449 | "10s",
1450 | "30s",
1451 | "1m",
1452 | "5m",
1453 | "15m",
1454 | "30m",
1455 | "1h",
1456 | "2h",
1457 | "1d"
1458 | ]
1459 | },
1460 | "timezone": "",
1461 | "title": "RuuviTag Dashboard",
1462 | "uid": "jcHKTQggz",
1463 | "version": 1
1464 | }
1465 |
--------------------------------------------------------------------------------