├── .gitignore ├── Dockerfile ├── README.md ├── adapter └── MqttConfig.go ├── app.go ├── controllers └── HealthController.go ├── db └── InfluxConfig.go ├── doc ├── architecture.excalidraw └── images │ └── architecture.png ├── go.mod ├── go.sum └── models ├── ChipEvent.go └── Health.go /.gitignore: -------------------------------------------------------------------------------- 1 | main 2 | mqtt-golang-subscriber 3 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.15-alpine 2 | 3 | ENV APP_NAME=mqtt-golang-subscriber 4 | ENV GIN_MODE=release 5 | ENV MQTT_HOST=mqtt.server.com 6 | ENV MQTT_PORT=1883 7 | ENV MQTT_CLIENT_NAME= 8 | ENV MQTT_TOPIC_NAME= 9 | ENV INFLUXDB_HOST=influxdb.server.com 10 | ENV INFLUXDB_DATABASE_NAME=iot 11 | ENV INFLUXDB_MEASUREMENT="" 12 | ENV PORT=8080 13 | 14 | WORKDIR /go/src/app 15 | COPY . . 16 | 17 | RUN go get -d -v ./... 18 | RUN go install -v ./... 19 | RUN rm -rf /go/src/app 20 | 21 | EXPOSE $PORT 22 | 23 | ENTRYPOINT $APP_NAME 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MQTT client for iot 2 | Nanoservice that suscribes just a Mqtt topic and save the data to InfluxDB. 3 | 4 | # Architecture 5 | ![Architecture schema](doc/images/architecture.png) 6 | 7 | # Run 8 | ## Docker 9 | ```bash 10 | # create dedicated network 11 | $ docker network create --driver bridge iot 12 | # run MongoDB container 13 | $ docker run -itd -p 1883:1883 -p 9001:9001 --name mosquitto --network iot eclipse-mosquitto:1.6 14 | # run InfluxDB container 15 | $ docker run -p 8086:8086 --name influx --network iot influxdb:1.8.4 16 | # create a database into Influx 17 | $ docker exec -it influx influx 18 | $ create database iot 19 | $ exit 20 | # run microservice container 21 | $ docker run -dit \ 22 | --env MQTT_HOST=mosquitto \ 23 | --env MQTT_PORT=1883 \ 24 | --env MQTT_TOPIC_NAME=/test/one \ 25 | --env INFLUXDB_HOST=http://influx:8086 \ 26 | --env INFLUXDB_DATABASE_NAME=iot \ 27 | --env INFLUXDB_MEASUREMENT=test \ 28 | --name ns-mqtt-suscriber -p 8080:8080 --network iot b0rr3g0/mqtt-golang-influxdb:latest 29 | ``` 30 | ## Kubernetes 31 | This microservice could be deployed using Helm. I recommend the following Helm Chart: [https://github.com/dbgjerez/ms-helm-chart](https://github.com/dbgjerez/ms-helm-chart). 32 | 33 | The configuration values.yaml that I have used: [values.yaml](https://github.com/dbgjerez/iot-k8s-stack/blob/master/mqtt-plants-suscriber/values.yaml) 34 | 35 | The healthcheck endpoint check MongoDB and Mqtt server connection. If anyone of both fails, it returns 500 http code. 36 | ```bash 37 | [GIN] 2021/02/13 - 20:59:51 | 200 | 594.029µs | 10.42.0.1 | GET "/api/v1/health" 38 | ``` 39 | 40 | # Configuration 41 | | Variable | Default value | Description | 42 | | ------ | ------ | ------ | 43 | | PORT | 8080 | Server port | 44 | | GIN_MODE | debug | Gin gonic mode. (release for production mode) | 45 | | MQTT_HOST | mqtt.server.com | Mqtt host | 46 | | MQTT_PORT | 1883 | Mqtt port | 47 | | MQTT_CLIENT_NAME | "" | Name of the ms when connect to Mqtt broker | 48 | | MQTT_TOPIC_NAME | "" | Topic to suscription | 49 | | INFLUXDB_HOST | "" | Influxdb host | 50 | | INFLUXDB_DATABASE_NAME | "" | Influxdb database name | 51 | | INFLUXDB_MEASUREMENT | "" | Influxdb measurement name for this nanoservice | 52 | 53 | # Libraries 54 | * Gin Gonic: Golang Framework 55 | * InfluxDB client: Connection with InfluxDB https://github.com/influxdata/influxdb-client-go 56 | * Mqtt client: Mqtt connection and listener https://github.com/eclipse/paho.mqtt.golang 57 | * GoDotEnv: Library for env variables 58 | -------------------------------------------------------------------------------- /adapter/MqttConfig.go: -------------------------------------------------------------------------------- 1 | package adapter 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "log" 7 | "mqtt-golang-subscriber/db" 8 | "mqtt-golang-subscriber/models" 9 | "os" 10 | 11 | mqtt "github.com/eclipse/paho.mqtt.golang" 12 | ) 13 | 14 | // mqtt constants 15 | const ( 16 | BrokerHostFormat = "tcp://%s:%s" // host yo mqtt 17 | MqttHost = "MQTT_HOST" // host env variable 18 | MqttPort = "MQTT_PORT" 19 | MqttClientName = "MQTT_CLIENT_NAME" 20 | MqttTopicName = "MQTT_TOPIC_NAME" 21 | ) 22 | 23 | var host = os.Getenv(MqttHost) 24 | var port = os.Getenv(MqttPort) 25 | 26 | type MqttConnection struct { 27 | mqttClient mqtt.Client 28 | } 29 | 30 | func NewConnection(clientId string) (conn *MqttConnection) { 31 | opts := mqtt.NewClientOptions() 32 | opts.AddBroker(fmt.Sprintf(BrokerHostFormat, host, port)) 33 | opts.SetClientID(clientId) 34 | opts.AutoReconnect = true 35 | opts.OnConnectionLost = connectLostHandler 36 | opts.OnConnect = connectHandler 37 | client := mqtt.NewClient(opts) 38 | if token := client.Connect(); token.Wait() && token.Error() != nil { 39 | log.Fatalln("Connect problem: ", token.Error()) 40 | } 41 | conn = &MqttConnection{client} 42 | return conn 43 | } 44 | 45 | func (conn *MqttConnection) Subscribe(influxConn *db.InfluxDBConnection, topic string) { 46 | token := conn.mqttClient.Subscribe(topic, 1, onMessageReceived(influxConn)) 47 | token.Wait() 48 | log.Println("Subscribed to topic: ", topic) 49 | } 50 | 51 | func (con *MqttConnection) IsConnected() bool { 52 | connected := con.mqttClient.IsConnected() 53 | if !connected { 54 | log.Println("Healthcheck MQTT fails") 55 | } 56 | return connected 57 | } 58 | 59 | func onMessageReceived(influxConn *db.InfluxDBConnection) func(client mqtt.Client, msg mqtt.Message) { 60 | return func(client mqtt.Client, msg mqtt.Message) { 61 | log.Printf("Received message: %s from topic: %s", msg.Payload(), msg.Topic()) 62 | 63 | event := models.ChipEvent{} 64 | 65 | err := json.Unmarshal([]byte(msg.Payload()), &event) 66 | if err != nil { 67 | log.Println("Unmarshal message fails: ", err) 68 | } 69 | 70 | influxConn.Insert(&event) 71 | } 72 | } 73 | 74 | var connectLostHandler mqtt.ConnectionLostHandler = func(client mqtt.Client, err error) { 75 | log.Println("Connection lost: ", err) 76 | } 77 | 78 | var connectHandler mqtt.OnConnectHandler = func(client mqtt.Client) { 79 | log.Println("Mqtt connected") 80 | } 81 | -------------------------------------------------------------------------------- /app.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "mqtt-golang-subscriber/adapter" 5 | "mqtt-golang-subscriber/controllers" 6 | "mqtt-golang-subscriber/db" 7 | "os" 8 | 9 | "github.com/gin-gonic/gin" 10 | ) 11 | 12 | func main() { 13 | router := gin.Default() 14 | 15 | influxDBConnection := db.NewConnection() 16 | 17 | mqttConnection := adapter.NewConnection(os.Getenv(adapter.MqttClientName)) 18 | mqttConnection.Subscribe(influxDBConnection, os.Getenv(adapter.MqttTopicName)) 19 | 20 | v1 := router.Group("/api/v1") 21 | { 22 | v1.GET("/health", controllers.HealthControllerHandler(mqttConnection, influxDBConnection)) 23 | } 24 | 25 | router.NoRoute(func(c *gin.Context) { 26 | c.JSON(404, gin.H{"msg": "Not found"}) 27 | }) 28 | 29 | router.Run(":8080") 30 | } 31 | -------------------------------------------------------------------------------- /controllers/HealthController.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "mqtt-golang-subscriber/adapter" 5 | "mqtt-golang-subscriber/db" 6 | "mqtt-golang-subscriber/models" 7 | "net/http" 8 | 9 | "github.com/gin-gonic/gin" 10 | ) 11 | 12 | type HealthController struct { 13 | } 14 | 15 | func HealthControllerHandler(mqttConn *adapter.MqttConnection, influxConn *db.InfluxDBConnection) func(c *gin.Context) { 16 | return func(c *gin.Context) { 17 | h := models.Health{} 18 | if mqttConn.IsConnected() && influxConn.IsConnected() { 19 | h.Status = models.HealhStatusUp 20 | c.JSON(http.StatusOK, h) 21 | } else { 22 | h.Status = models.HealhStatusDown 23 | c.JSON(http.StatusInternalServerError, h) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /db/InfluxConfig.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "mqtt-golang-subscriber/models" 7 | "os" 8 | "time" 9 | 10 | influxdb2 "github.com/influxdata/influxdb-client-go/v2" 11 | ) 12 | 13 | // Influxdb constants 14 | const ( 15 | InfluxDBHost = "INFLUXDB_HOST" 16 | InfluxDBDatabaseName = "INFLUXDB_DATABASE_NAME" 17 | InfluxDBMeasurement = "INFLUXDB_MEASUREMENT" 18 | ) 19 | 20 | type InfluxDBConnection struct { 21 | influxdbClient influxdb2.Client 22 | } 23 | 24 | func NewConnection() (conn *InfluxDBConnection) { 25 | influxdb2.DefaultOptions().HTTPClient() 26 | client := influxdb2.NewClient(os.Getenv(InfluxDBHost), "") 27 | conn = &InfluxDBConnection{client} 28 | return conn 29 | } 30 | 31 | func (conn *InfluxDBConnection) IsConnected() bool { 32 | _, err := conn.influxdbClient.Health(context.Background()) 33 | if err != nil { 34 | log.Println("Healthcheck InfluxDB fails: ", err) 35 | return false 36 | } 37 | return true 38 | } 39 | 40 | func (conn *InfluxDBConnection) Insert(event *models.ChipEvent) { 41 | for _, elem := range event.Sensors { 42 | p := influxdb2.NewPointWithMeasurement(os.Getenv(InfluxDBMeasurement)). 43 | AddTag("chip", event.Chip). 44 | AddTag("sensor", elem.Sensor). 45 | AddField("battery", event.Battery). 46 | AddField("humidity", elem.Humidity). 47 | SetTime(time.Unix(elem.Time, 0)) 48 | 49 | writeAPI := conn.influxdbClient.WriteAPIBlocking("", os.Getenv(InfluxDBDatabaseName)) 50 | err := writeAPI.WritePoint(context.Background(), p) 51 | if err != nil { 52 | log.Println("Influxdb fails insert: ", err) 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /doc/architecture.excalidraw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "excalidraw", 3 | "version": 2, 4 | "source": "https://excalidraw.com", 5 | "elements": [ 6 | { 7 | "type": "rectangle", 8 | "version": 297, 9 | "versionNonce": 1246813354, 10 | "isDeleted": false, 11 | "id": "xtFMroWdNhvqCU2bBxcG9", 12 | "fillStyle": "hachure", 13 | "strokeWidth": 1, 14 | "strokeStyle": "solid", 15 | "roughness": 2, 16 | "opacity": 100, 17 | "angle": 0, 18 | "x": 723, 19 | "y": -162, 20 | "strokeColor": "#000000", 21 | "backgroundColor": "#fd7e14", 22 | "width": 154.00000000000003, 23 | "height": 81, 24 | "seed": 1998553995, 25 | "groupIds": [], 26 | "strokeSharpness": "round", 27 | "boundElementIds": [ 28 | "5McWPcrxsOkxoZXqM-DAh", 29 | "DZFzHPaKwn8mjh3xvdmC2", 30 | "QVcJ-T7qVGgJLG1hg9YFP", 31 | "-N8AqC6NMErBi-wD_zdB0", 32 | "UFKnsOMwwdnnWCcLIsXa3", 33 | "pcP9AJG56XCE9fO7EaIxQ", 34 | "mAO1ydTJIG7sWYJuQEZc0", 35 | "djeEFMJHizMkTpCEepTDM", 36 | "N96ugHTJAHdtpTa-5NmJk" 37 | ] 38 | }, 39 | { 40 | "type": "line", 41 | "version": 5026, 42 | "versionNonce": 800035114, 43 | "isDeleted": false, 44 | "id": "uN8wRQSNltIIUbzNuZ8s2", 45 | "fillStyle": "hachure", 46 | "strokeWidth": 1, 47 | "strokeStyle": "solid", 48 | "roughness": 1, 49 | "opacity": 100, 50 | "angle": 1.5707963267948957, 51 | "x": 448.630944962513, 52 | "y": -146.34779739627265, 53 | "strokeColor": "#087f5b", 54 | "backgroundColor": "#40c057", 55 | "width": 52.317507746132115, 56 | "height": 154.56722543646003, 57 | "seed": 250339045, 58 | "groupIds": [ 59 | "ydaetD5qrznL-Zee28k6m", 60 | "10a1EfcI0eEdw5LSW4MBi" 61 | ], 62 | "strokeSharpness": "round", 63 | "boundElementIds": [], 64 | "startBinding": null, 65 | "endBinding": null, 66 | "points": [ 67 | [ 68 | -0.24755378372925183, 69 | -40.169554027464216 70 | ], 71 | [ 72 | -0.07503751055611152, 73 | 76.6515171914404 74 | ], 75 | [ 76 | -0.23948042713317108, 77 | 89.95108885873196 78 | ], 79 | [ 80 | 2.446913573036335, 81 | 95.69766931810295 82 | ], 83 | [ 84 | 11.802146636255692, 85 | 100.56113713047068 86 | ], 87 | [ 88 | 27.615140546177496, 89 | 102.07554835500338 90 | ], 91 | [ 92 | 42.72341054254274, 93 | 99.65756899883291 94 | ], 95 | [ 96 | 50.75054563137204, 97 | 93.87501510096598 98 | ], 99 | [ 100 | 51.88266441510958, 101 | 89.00026150397161 102 | ], 103 | [ 104 | 52.04166639997853, 105 | 78.29287333983132 106 | ], 107 | [ 108 | 51.916868330459295, 109 | -30.36891819848148 110 | ], 111 | [ 112 | 51.635533423123285, 113 | -40.63545540065934 114 | ], 115 | [ 116 | 48.27622163143906, 117 | -46.37349057843314 118 | ], 119 | [ 120 | 41.202227904674494, 121 | -49.69665692879073 122 | ], 123 | [ 124 | 25.081551986374073, 125 | -52.49167708145666 126 | ], 127 | [ 128 | 12.15685839679867, 129 | -50.825000270901 130 | ], 131 | [ 132 | 1.9916746648394732, 133 | -45.171835889467935 134 | ], 135 | [ 136 | -0.2758413461535838, 137 | -40.23974757720194 138 | ], 139 | [ 140 | -0.24755378372925183, 141 | -40.169554027464216 142 | ] 143 | ], 144 | "lastCommittedPoint": null, 145 | "startArrowhead": null, 146 | "endArrowhead": null 147 | }, 148 | { 149 | "type": "line", 150 | "version": 2665, 151 | "versionNonce": 296545910, 152 | "isDeleted": false, 153 | "id": "9NrHNp5tGzgSswWLGwqrI", 154 | "fillStyle": "solid", 155 | "strokeWidth": 1, 156 | "strokeStyle": "solid", 157 | "roughness": 1, 158 | "opacity": 100, 159 | "angle": 1.5707963267948957, 160 | "x": 423.8559807744268, 161 | "y": -125.39182314573304, 162 | "strokeColor": "#087f5b", 163 | "backgroundColor": "transparent", 164 | "width": 50.7174766392476, 165 | "height": 12.698053371678215, 166 | "seed": 225553899, 167 | "groupIds": [ 168 | "ydaetD5qrznL-Zee28k6m", 169 | "10a1EfcI0eEdw5LSW4MBi" 170 | ], 171 | "strokeSharpness": "round", 172 | "boundElementIds": [], 173 | "startBinding": null, 174 | "endBinding": null, 175 | "points": [ 176 | [ 177 | 0, 178 | -2.0205717204386002 179 | ], 180 | [ 181 | 1.3361877396713384, 182 | 3.0410845646550486 183 | ], 184 | [ 185 | 7.098613049589299, 186 | 7.287767671898479 187 | ], 188 | [ 189 | 14.766422451441104, 190 | 9.859533283467512 191 | ], 192 | [ 193 | 26.779003528407447, 194 | 10.093886705011586 195 | ], 196 | [ 197 | 40.79727342221974, 198 | 8.456559589697127 199 | ], 200 | [ 201 | 48.98410145879092, 202 | 2.500000505196364 203 | ], 204 | [ 205 | 50.7174766392476, 206 | -2.6041666666666288 207 | ] 208 | ], 209 | "lastCommittedPoint": null, 210 | "startArrowhead": null, 211 | "endArrowhead": null 212 | }, 213 | { 214 | "type": "line", 215 | "version": 2798, 216 | "versionNonce": 1589107690, 217 | "isDeleted": false, 218 | "id": "1tHn0TkF0Tq9IN3Fabg-z", 219 | "fillStyle": "solid", 220 | "strokeWidth": 1, 221 | "strokeStyle": "solid", 222 | "roughness": 1, 223 | "opacity": 100, 224 | "angle": 1.5707963267948957, 225 | "x": 469.2817619228688, 226 | "y": -124.93695280430916, 227 | "strokeColor": "#087f5b", 228 | "backgroundColor": "transparent", 229 | "width": 50.57247907260371, 230 | "height": 10.178760037658167, 231 | "seed": 2117646917, 232 | "groupIds": [ 233 | "ydaetD5qrznL-Zee28k6m", 234 | "10a1EfcI0eEdw5LSW4MBi" 235 | ], 236 | "strokeSharpness": "round", 237 | "boundElementIds": [], 238 | "startBinding": null, 239 | "endBinding": null, 240 | "points": [ 241 | [ 242 | 0, 243 | -2.136356936862347 244 | ], 245 | [ 246 | 1.332367676378171, 247 | 1.9210669226078037 248 | ], 249 | [ 250 | 7.078318632616268, 251 | 5.325208253515953 252 | ], 253 | [ 254 | 14.724206326638113, 255 | 7.386735659885842 256 | ], 257 | [ 258 | 26.70244431044034, 259 | 7.574593370991538 260 | ], 261 | [ 262 | 40.68063699304561, 263 | 6.262111896696538 264 | ], 265 | [ 266 | 48.84405948536458, 267 | 1.4873339211608216 268 | ], 269 | [ 270 | 50.57247907260371, 271 | -2.6041666666666288 272 | ] 273 | ], 274 | "lastCommittedPoint": null, 275 | "startArrowhead": null, 276 | "endArrowhead": null 277 | }, 278 | { 279 | "type": "ellipse", 280 | "version": 5771, 281 | "versionNonce": 1848881078, 282 | "isDeleted": false, 283 | "id": "RZBShZwmmYnjWfGNWwMvo", 284 | "fillStyle": "solid", 285 | "strokeWidth": 1, 286 | "strokeStyle": "solid", 287 | "roughness": 1, 288 | "opacity": 100, 289 | "angle": 1.5707963267948957, 290 | "x": 515.8865350549838, 291 | "y": -132.92650566205975, 292 | "strokeColor": "#087f5b", 293 | "backgroundColor": "#fff", 294 | "width": 51.27812853552538, 295 | "height": 22.797152568995934, 296 | "seed": 712685707, 297 | "groupIds": [ 298 | "ydaetD5qrznL-Zee28k6m", 299 | "10a1EfcI0eEdw5LSW4MBi" 300 | ], 301 | "strokeSharpness": "sharp", 302 | "boundElementIds": [ 303 | "bxuMGTzXLn7H-uBCptINx", 304 | "5McWPcrxsOkxoZXqM-DAh", 305 | "mAO1ydTJIG7sWYJuQEZc0" 306 | ] 307 | }, 308 | { 309 | "id": "LntjHKw3dDKvCiCbT4eyn", 310 | "type": "text", 311 | "x": 436.2896988355791, 312 | "y": -88.56418467804264, 313 | "width": 67, 314 | "height": 25, 315 | "angle": 0, 316 | "strokeColor": "#000000", 317 | "backgroundColor": "transparent", 318 | "fillStyle": "hachure", 319 | "strokeWidth": 1, 320 | "strokeStyle": "solid", 321 | "roughness": 2, 322 | "opacity": 100, 323 | "groupIds": [ 324 | "10a1EfcI0eEdw5LSW4MBi" 325 | ], 326 | "strokeSharpness": "round", 327 | "seed": 1951563562, 328 | "version": 200, 329 | "versionNonce": 65588906, 330 | "isDeleted": false, 331 | "boundElementIds": null, 332 | "text": "MQTT", 333 | "fontSize": 20, 334 | "fontFamily": 1, 335 | "textAlign": "center", 336 | "verticalAlign": "middle", 337 | "baseline": 18 338 | }, 339 | { 340 | "type": "line", 341 | "version": 4400, 342 | "versionNonce": 651184374, 343 | "isDeleted": false, 344 | "id": "wIB0YX_r-3dIiO_68fbnu", 345 | "fillStyle": "solid", 346 | "strokeWidth": 1, 347 | "strokeStyle": "solid", 348 | "roughness": 1, 349 | "opacity": 100, 350 | "angle": 0, 351 | "x": 766.4940208768828, 352 | "y": 96.56292520474358, 353 | "strokeColor": "#0a11d3", 354 | "backgroundColor": "#228be6", 355 | "width": 88.21658171083376, 356 | "height": 113.8575037534261, 357 | "seed": 1084788394, 358 | "groupIds": [ 359 | "43ZND2f5QbsMscvAKx7Tq" 360 | ], 361 | "strokeSharpness": "round", 362 | "boundElementIds": [], 363 | "startBinding": null, 364 | "endBinding": null, 365 | "points": [ 366 | [ 367 | -0.22814350714115691, 368 | -43.414939319563715 369 | ], 370 | [ 371 | 0.06274947619197979, 372 | 42.63794490105306 373 | ], 374 | [ 375 | -0.21453039840335475, 376 | 52.43469208825097 377 | ], 378 | [ 379 | 4.315205554872581, 380 | 56.66774540453215 381 | ], 382 | [ 383 | 20.089784992984285, 384 | 60.25027917349701 385 | ], 386 | [ 387 | 46.7532926683984, 388 | 61.365826671969444 389 | ], 390 | [ 391 | 72.22851104292477, 392 | 59.584691681394986 393 | ], 394 | [ 395 | 85.76368213524371, 396 | 55.325139565662596 397 | ], 398 | [ 399 | 87.67263486434864, 400 | 51.7342924478499 401 | ], 402 | [ 403 | 87.94074036468018, 404 | 43.84700272879395 405 | ], 406 | [ 407 | 87.73030872197806, 408 | -36.195582644606276 409 | ], 410 | [ 411 | 87.2559282533682, 412 | -43.758132174307036 413 | ], 414 | [ 415 | 81.5915337527493, 416 | -47.984890854524416 417 | ], 418 | [ 419 | 69.66352776578219, 420 | -50.4328058257654 421 | ], 422 | [ 423 | 42.481213744224995, 424 | -52.49167708145666 425 | ], 426 | [ 427 | 20.68789182864576, 428 | -51.26396751574663 429 | ], 430 | [ 431 | 3.5475921483286084, 432 | -47.099726468136254 433 | ], 434 | [ 435 | -0.2758413461535838, 436 | -43.46664538034193 437 | ], 438 | [ 439 | -0.22814350714115691, 440 | -43.414939319563715 441 | ] 442 | ], 443 | "lastCommittedPoint": null, 444 | "startArrowhead": null, 445 | "endArrowhead": null 446 | }, 447 | { 448 | "type": "line", 449 | "version": 2134, 450 | "versionNonce": 602761578, 451 | "isDeleted": false, 452 | "id": "xYqMpkz_bNQjYhkWsieAs", 453 | "fillStyle": "solid", 454 | "strokeWidth": 1, 455 | "strokeStyle": "solid", 456 | "roughness": 1, 457 | "opacity": 100, 458 | "angle": 0, 459 | "x": 766.9532389592389, 460 | "y": 120.59197418672841, 461 | "strokeColor": "#0a11d3", 462 | "backgroundColor": "transparent", 463 | "width": 88.30808627974527, 464 | "height": 9.797916664247975, 465 | "seed": 1726777590, 466 | "groupIds": [ 467 | "43ZND2f5QbsMscvAKx7Tq" 468 | ], 469 | "strokeSharpness": "round", 470 | "boundElementIds": [], 471 | "startBinding": null, 472 | "endBinding": null, 473 | "points": [ 474 | [ 475 | 0, 476 | -2.1538602707609424 477 | ], 478 | [ 479 | 2.326538897826852, 480 | 1.751753055375216 481 | ], 482 | [ 483 | 12.359939318521995, 484 | 5.028526743934819 485 | ], 486 | [ 487 | 25.710950037209347, 488 | 7.012921076245119 489 | ], 490 | [ 491 | 46.6269757640547, 492 | 7.193749997581346 493 | ], 494 | [ 495 | 71.03526003420632, 496 | 5.930375670950649 497 | ], 498 | [ 499 | 85.2899738827162, 500 | 1.3342483900732343 501 | ], 502 | [ 503 | 88.30808627974527, 504 | -2.6041666666666288 505 | ] 506 | ], 507 | "lastCommittedPoint": null, 508 | "startArrowhead": null, 509 | "endArrowhead": null 510 | }, 511 | { 512 | "type": "line", 513 | "version": 2231, 514 | "versionNonce": 1795668534, 515 | "isDeleted": false, 516 | "id": "7T05SGNTYwpWbiC1rHvzU", 517 | "fillStyle": "solid", 518 | "strokeWidth": 1, 519 | "strokeStyle": "solid", 520 | "roughness": 1, 521 | "opacity": 100, 522 | "angle": 0, 523 | "x": 765.8594974471775, 524 | "y": 87.5178196246568, 525 | "strokeColor": "#0a11d3", 526 | "backgroundColor": "transparent", 527 | "width": 88.30808627974527, 528 | "height": 9.797916664247975, 529 | "seed": 850733418, 530 | "groupIds": [ 531 | "43ZND2f5QbsMscvAKx7Tq" 532 | ], 533 | "strokeSharpness": "round", 534 | "boundElementIds": [], 535 | "startBinding": null, 536 | "endBinding": null, 537 | "points": [ 538 | [ 539 | 0, 540 | -2.1538602707609424 541 | ], 542 | [ 543 | 2.326538897826852, 544 | 1.751753055375216 545 | ], 546 | [ 547 | 12.359939318521995, 548 | 5.028526743934819 549 | ], 550 | [ 551 | 25.710950037209347, 552 | 7.012921076245119 553 | ], 554 | [ 555 | 46.6269757640547, 556 | 7.193749997581346 557 | ], 558 | [ 559 | 71.03526003420632, 560 | 5.930375670950649 561 | ], 562 | [ 563 | 85.2899738827162, 564 | 1.3342483900732343 565 | ], 566 | [ 567 | 88.30808627974527, 568 | -2.6041666666666288 569 | ] 570 | ], 571 | "lastCommittedPoint": null, 572 | "startArrowhead": null, 573 | "endArrowhead": null 574 | }, 575 | { 576 | "type": "ellipse", 577 | "version": 5253, 578 | "versionNonce": 1323470518, 579 | "isDeleted": false, 580 | "id": "SeAtVTLW6OTW1GF6EGP79", 581 | "fillStyle": "solid", 582 | "strokeWidth": 1, 583 | "strokeStyle": "solid", 584 | "roughness": 1, 585 | "opacity": 100, 586 | "angle": 0, 587 | "x": 764.7386747610158, 588 | "y": 45.12328965808376, 589 | "strokeColor": "#0a11d3", 590 | "backgroundColor": "#fff", 591 | "width": 87.65074610854188, 592 | "height": 17.72670397681366, 593 | "seed": 1570503222, 594 | "groupIds": [ 595 | "43ZND2f5QbsMscvAKx7Tq" 596 | ], 597 | "strokeSharpness": "sharp", 598 | "boundElementIds": [ 599 | "bxuMGTzXLn7H-uBCptINx", 600 | "UFKnsOMwwdnnWCcLIsXa3", 601 | "djeEFMJHizMkTpCEepTDM", 602 | "N96ugHTJAHdtpTa-5NmJk" 603 | ] 604 | }, 605 | { 606 | "type": "ellipse", 607 | "version": 608, 608 | "versionNonce": 272471786, 609 | "isDeleted": false, 610 | "id": "_GY9fpDeVLeLkR5kwGOhY", 611 | "fillStyle": "solid", 612 | "strokeWidth": 1, 613 | "strokeStyle": "solid", 614 | "roughness": 1, 615 | "opacity": 100, 616 | "angle": 0, 617 | "x": 836.2484070615965, 618 | "y": 69.69909253521706, 619 | "strokeColor": "#0a11d3", 620 | "backgroundColor": "#fff", 621 | "width": 12.846057046979809, 622 | "height": 13.941904362416096, 623 | "seed": 1440771114, 624 | "groupIds": [ 625 | "43ZND2f5QbsMscvAKx7Tq" 626 | ], 627 | "strokeSharpness": "sharp", 628 | "boundElementIds": [] 629 | }, 630 | { 631 | "type": "ellipse", 632 | "version": 657, 633 | "versionNonce": 1295721654, 634 | "isDeleted": false, 635 | "id": "cFPNbuYKtTAHgKURfZVqd", 636 | "fillStyle": "solid", 637 | "strokeWidth": 1, 638 | "strokeStyle": "solid", 639 | "roughness": 1, 640 | "opacity": 100, 641 | "angle": 0, 642 | "x": 836.2484070615965, 643 | "y": 100.30154639427724, 644 | "strokeColor": "#0a11d3", 645 | "backgroundColor": "#fff", 646 | "width": 12.846057046979809, 647 | "height": 13.941904362416096, 648 | "seed": 1204503414, 649 | "groupIds": [ 650 | "43ZND2f5QbsMscvAKx7Tq" 651 | ], 652 | "strokeSharpness": "sharp", 653 | "boundElementIds": [] 654 | }, 655 | { 656 | "type": "ellipse", 657 | "version": 711, 658 | "versionNonce": 318712234, 659 | "isDeleted": false, 660 | "id": "tCs4FEOK89lW0B6m3nNsr", 661 | "fillStyle": "solid", 662 | "strokeWidth": 1, 663 | "strokeStyle": "solid", 664 | "roughness": 1, 665 | "opacity": 100, 666 | "angle": 0, 667 | "x": 836.2484070615965, 668 | "y": 133.56234756877382, 669 | "strokeColor": "#0a11d3", 670 | "backgroundColor": "#fff", 671 | "width": 12.846057046979809, 672 | "height": 13.941904362416096, 673 | "seed": 1612011242, 674 | "groupIds": [ 675 | "43ZND2f5QbsMscvAKx7Tq" 676 | ], 677 | "strokeSharpness": "sharp", 678 | "boundElementIds": [] 679 | }, 680 | { 681 | "id": "a33O2ROARGj9GJhENxj55", 682 | "type": "text", 683 | "x": 766, 684 | "y": 165, 685 | "width": 91, 686 | "height": 25, 687 | "angle": 0, 688 | "strokeColor": "#000000", 689 | "backgroundColor": "transparent", 690 | "fillStyle": "hachure", 691 | "strokeWidth": 1, 692 | "strokeStyle": "solid", 693 | "roughness": 2, 694 | "opacity": 100, 695 | "groupIds": [ 696 | "43ZND2f5QbsMscvAKx7Tq" 697 | ], 698 | "strokeSharpness": "round", 699 | "seed": 1887900598, 700 | "version": 332, 701 | "versionNonce": 2132876790, 702 | "isDeleted": false, 703 | "boundElementIds": null, 704 | "text": "InfluxDB", 705 | "fontSize": 20, 706 | "fontFamily": 1, 707 | "textAlign": "left", 708 | "verticalAlign": "top", 709 | "baseline": 18 710 | }, 711 | { 712 | "id": "ZyvVi1enrUlMIpyTQkDsj", 713 | "type": "text", 714 | "x": 563, 715 | "y": -145, 716 | "width": 110, 717 | "height": 25, 718 | "angle": 6.193871314186364, 719 | "strokeColor": "#000000", 720 | "backgroundColor": "transparent", 721 | "fillStyle": "hachure", 722 | "strokeWidth": 1, 723 | "strokeStyle": "solid", 724 | "roughness": 2, 725 | "opacity": 100, 726 | "groupIds": [ 727 | "pGWUmwQtXm27dfgHmxl-Y" 728 | ], 729 | "strokeSharpness": "round", 730 | "seed": 207877162, 731 | "version": 230, 732 | "versionNonce": 1642033910, 733 | "isDeleted": false, 734 | "boundElementIds": [ 735 | "mAO1ydTJIG7sWYJuQEZc0" 736 | ], 737 | "text": "topic (json)", 738 | "fontSize": 20, 739 | "fontFamily": 1, 740 | "textAlign": "left", 741 | "verticalAlign": "top", 742 | "baseline": 18 743 | }, 744 | { 745 | "id": "mAO1ydTJIG7sWYJuQEZc0", 746 | "type": "arrow", 747 | "x": 560.9285904439716, 748 | "y": -112.10401367926323, 749 | "width": 152.07140955602836, 750 | "height": 5.2157582371229125, 751 | "angle": 0, 752 | "strokeColor": "#000000", 753 | "backgroundColor": "transparent", 754 | "fillStyle": "hachure", 755 | "strokeWidth": 1, 756 | "strokeStyle": "solid", 757 | "roughness": 2, 758 | "opacity": 100, 759 | "groupIds": [ 760 | "pGWUmwQtXm27dfgHmxl-Y" 761 | ], 762 | "strokeSharpness": "round", 763 | "seed": 1763777130, 764 | "version": 417, 765 | "versionNonce": 1144905578, 766 | "isDeleted": false, 767 | "boundElementIds": null, 768 | "points": [ 769 | [ 770 | 0, 771 | 0 772 | ], 773 | [ 774 | 152.07140955602836, 775 | -5.2157582371229125 776 | ] 777 | ], 778 | "lastCommittedPoint": null, 779 | "startBinding": { 780 | "elementId": "ZyvVi1enrUlMIpyTQkDsj", 781 | "focus": 1.1884118666459338, 782 | "gap": 3.6631578877313586 783 | }, 784 | "endBinding": { 785 | "elementId": "xtFMroWdNhvqCU2bBxcG9", 786 | "focus": -0.027729907566974795, 787 | "gap": 10 788 | }, 789 | "startArrowhead": null, 790 | "endArrowhead": "arrow" 791 | }, 792 | { 793 | "id": "P5hvmL-wdUHdbEZ7t-rc4", 794 | "type": "text", 795 | "x": 758, 796 | "y": -135, 797 | "width": 88, 798 | "height": 25, 799 | "angle": 0, 800 | "strokeColor": "#000000", 801 | "backgroundColor": "transparent", 802 | "fillStyle": "hachure", 803 | "strokeWidth": 1, 804 | "strokeStyle": "solid", 805 | "roughness": 2, 806 | "opacity": 100, 807 | "groupIds": [], 808 | "strokeSharpness": "round", 809 | "seed": 1286224886, 810 | "version": 115, 811 | "versionNonce": 1369348214, 812 | "isDeleted": false, 813 | "boundElementIds": null, 814 | "text": "ns-golang", 815 | "fontSize": 20, 816 | "fontFamily": 1, 817 | "textAlign": "left", 818 | "verticalAlign": "top", 819 | "baseline": 18 820 | }, 821 | { 822 | "id": "N96ugHTJAHdtpTa-5NmJk", 823 | "type": "arrow", 824 | "x": 805.7877719708486, 825 | "y": -69, 826 | "width": 0.1547495520396751, 827 | "height": 108.01994189125548, 828 | "angle": 0, 829 | "strokeColor": "#000000", 830 | "backgroundColor": "transparent", 831 | "fillStyle": "hachure", 832 | "strokeWidth": 1, 833 | "strokeStyle": "solid", 834 | "roughness": 2, 835 | "opacity": 100, 836 | "groupIds": [ 837 | "gnEWJWvf6spXibR9Mm_o_" 838 | ], 839 | "strokeSharpness": "round", 840 | "seed": 1982101226, 841 | "version": 339, 842 | "versionNonce": 1667796202, 843 | "isDeleted": false, 844 | "boundElementIds": null, 845 | "points": [ 846 | [ 847 | 0, 848 | 0 849 | ], 850 | [ 851 | 0.1547495520396751, 852 | 108.01994189125548 853 | ] 854 | ], 855 | "lastCommittedPoint": null, 856 | "startBinding": { 857 | "elementId": "xtFMroWdNhvqCU2bBxcG9", 858 | "focus": -0.07413323563768094, 859 | "gap": 12 860 | }, 861 | "endBinding": { 862 | "elementId": "SeAtVTLW6OTW1GF6EGP79", 863 | "focus": -0.059328299626379116, 864 | "gap": 6.118782188113515 865 | }, 866 | "startArrowhead": null, 867 | "endArrowhead": "arrow" 868 | }, 869 | { 870 | "id": "MAN3wIfNr7VBzaUJoAKaS", 871 | "type": "text", 872 | "x": 818, 873 | "y": -33, 874 | "width": 122, 875 | "height": 25, 876 | "angle": 0, 877 | "strokeColor": "#000000", 878 | "backgroundColor": "transparent", 879 | "fillStyle": "hachure", 880 | "strokeWidth": 1, 881 | "strokeStyle": "solid", 882 | "roughness": 2, 883 | "opacity": 100, 884 | "groupIds": [ 885 | "gnEWJWvf6spXibR9Mm_o_" 886 | ], 887 | "strokeSharpness": "round", 888 | "seed": 152712694, 889 | "version": 111, 890 | "versionNonce": 1449138614, 891 | "isDeleted": false, 892 | "boundElementIds": null, 893 | "text": "measurement", 894 | "fontSize": 20, 895 | "fontFamily": 1, 896 | "textAlign": "left", 897 | "verticalAlign": "top", 898 | "baseline": 18 899 | } 900 | ], 901 | "appState": { 902 | "gridSize": null, 903 | "viewBackgroundColor": "#ffffff" 904 | } 905 | } -------------------------------------------------------------------------------- /doc/images/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbgjerez/mqtt-golang-influxdb/16ac142d8eb43f643857192385d53f71414dda56/doc/images/architecture.png -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module mqtt-golang-subscriber 2 | 3 | go 1.15 4 | 5 | require ( 6 | github.com/eclipse/paho.mqtt.golang v1.3.1 7 | github.com/gin-gonic/gin v1.6.3 8 | github.com/influxdata/influxdb-client-go/v2 v2.2.2 9 | github.com/joho/godotenv v1.3.0 // indirect 10 | ) 11 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/deepmap/oapi-codegen v1.3.13 h1:9HKGCsdJqE4dnrQ8VerFS0/1ZOJPmAhN+g8xgp8y3K4= 5 | github.com/deepmap/oapi-codegen v1.3.13/go.mod h1:WAmG5dWY8/PYHt4vKxlt90NsbHMAOCiteYKZMiIRfOo= 6 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 7 | github.com/eclipse/paho.mqtt.golang v1.3.1 h1:6F5FYb1hxVSZS+p0ji5xBQamc5ltOolTYRy5R15uVmI= 8 | github.com/eclipse/paho.mqtt.golang v1.3.1/go.mod h1:eTzb4gxwwyWpqBUHGQZ4ABAV7+Jgm1PklsYT/eo8Hcc= 9 | github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw= 10 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 11 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 12 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 13 | github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= 14 | github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= 15 | github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= 16 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 17 | github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= 18 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= 19 | github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= 20 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= 21 | github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= 22 | github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= 23 | github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= 24 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 25 | github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= 26 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 27 | github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= 28 | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 29 | github.com/influxdata/influxdb-client-go v1.4.0 h1:+KavOkwhLClHFfYcJMHHnTL5CZQhXJzOm5IKHI9BqJk= 30 | github.com/influxdata/influxdb-client-go/v2 v2.2.2 h1:O0CGIuIwQafvAxttAJ/VqMKfbWWn2Mt8rbOmaM2Zj4w= 31 | github.com/influxdata/influxdb-client-go/v2 v2.2.2/go.mod h1:fa/d1lAdUHxuc1jedx30ZfNG573oQTQmUni3N6pcW+0= 32 | github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU= 33 | github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= 34 | github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= 35 | github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= 36 | github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= 37 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 38 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 39 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 40 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 41 | github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= 42 | github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= 43 | github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= 44 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 45 | github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= 46 | github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 47 | github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 48 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 49 | github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= 50 | github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= 51 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 52 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 53 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= 54 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 55 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= 56 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 57 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 58 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 59 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 60 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 61 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 62 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 63 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 64 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 65 | github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= 66 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= 67 | github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= 68 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 69 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 70 | github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= 71 | github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= 72 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 73 | golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 74 | golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 75 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 76 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 77 | golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 78 | golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0 h1:Jcxah/M+oLZ/R4/z5RzfPzGbPXnVDPkEDtf2JnuxN+U= 79 | golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 80 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 81 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 82 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 83 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 84 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 85 | golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 86 | golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 87 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= 88 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 89 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= 90 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 91 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 92 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 93 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 94 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 95 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 96 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 97 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 98 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 99 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 100 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 101 | gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= 102 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 103 | -------------------------------------------------------------------------------- /models/ChipEvent.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type ChipEvent struct { 4 | Chip string `json:"chip"` 5 | Battery int64 `json:"battery,string,omitempty"` 6 | Sensors []struct { 7 | Sensor string `json:"sensor"` 8 | Time int64 `json:"time"` 9 | Humidity int `json:"humidity"` 10 | } `json:"sensors"` 11 | } 12 | -------------------------------------------------------------------------------- /models/Health.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | // health status 4 | const ( 5 | HealhStatusUp = "UP" 6 | HealhStatusDown = "DOWN" 7 | ) 8 | 9 | type Health struct { 10 | Status string `json:"status"` 11 | } 12 | --------------------------------------------------------------------------------