Browse Source

show current state of lights.

Thomas Buck 1 year ago
parent
commit
a97051aad9
3 changed files with 117 additions and 7 deletions
  1. 46
    0
      Makefile
  2. 4
    0
      README.md
  3. 67
    7
      lights-telegram.go

+ 46
- 0
Makefile View File

1
+# ----------------------------------------------------------------------------
2
+# "THE BEER-WARE LICENSE" (Revision 42):
3
+# <xythobuz@xythobuz.de> wrote this file.  As long as you retain this notice
4
+# you can do whatever you want with this stuff. If we meet some day, and you
5
+# think this stuff is worth it, you can buy me a beer in return.   Thomas Buck
6
+# ----------------------------------------------------------------------------
7
+
8
+HOST = iot
9
+
10
+# ----------------------------------------------------------------------------
11
+
12
+# https://tech.davis-hansson.com/p/make/
13
+
14
+SHELL := bash
15
+.ONESHELL:
16
+.SHELLFLAGS := -eu -o pipefail -c
17
+.DELETE_ON_ERROR:
18
+MAKEFLAGS += --warn-undefined-variables
19
+MAKEFLAGS += --no-builtin-rules
20
+
21
+# check for recent make
22
+ifeq ($(origin .RECIPEPREFIX), undefined)
23
+  $(error This Make does not support .RECIPEPREFIX. Please use GNU Make 4.0 or later)
24
+endif
25
+.RECIPEPREFIX = >
26
+
27
+# ----------------------------------------------------------------------------
28
+
29
+all: lights-telegram
30
+
31
+lights-telegram: lights-telegram.go
32
+> CGO_ENABLED=0 go build
33
+
34
+clean:
35
+> rm -rf lights-telegram
36
+
37
+upload: lights-telegram
38
+> ssh $(HOST) sudo systemctl stop lights-telegram
39
+> scp lights-telegram $(HOST):~/bin/lights-telegram/lights-telegram
40
+> sleep 1
41
+> ssh $(HOST) sudo systemctl start lights-telegram
42
+.PHONY: upload
43
+
44
+download:
45
+> scp $(HOST):~/bin/lights-telegram/config.yaml config.yaml
46
+.PHONY: download

+ 4
- 0
README.md View File

41
     systemctl daemon-reload
41
     systemctl daemon-reload
42
     systemctl enable --now lights-telegram
42
     systemctl enable --now lights-telegram
43
 
43
 
44
+You can also look at the log output of the app.
45
+
46
+    journalctl -u lights-telegram -b -f
47
+
44
 ## Dependencies
48
 ## Dependencies
45
 
49
 
46
  * [tgbotapi](https://pkg.go.dev/github.com/go-telegram-bot-api/telegram-bot-api/v5)
50
  * [tgbotapi](https://pkg.go.dev/github.com/go-telegram-bot-api/telegram-bot-api/v5)

+ 67
- 7
lights-telegram.go View File

25
     Name string `yaml:"name"`
25
     Name string `yaml:"name"`
26
     Topic string `yaml:"topic"`
26
     Topic string `yaml:"topic"`
27
     Values []string `yaml:"values"`
27
     Values []string `yaml:"values"`
28
+    lastValue string
28
 }
29
 }
29
 
30
 
30
 type Config struct {
31
 type Config struct {
155
     }
156
     }
156
 }
157
 }
157
 
158
 
158
-func sendKeyboardReply(name string, chat int64, message int) {
159
+func sendKeyboardReply(text string, name string, chat int64, message int) {
159
     var rows [][]tgbotapi.KeyboardButton
160
     var rows [][]tgbotapi.KeyboardButton
160
     for reg := range config.Registration {
161
     for reg := range config.Registration {
161
         if name == config.Registration[reg].Name {
162
         if name == config.Registration[reg].Name {
168
     }
169
     }
169
     keyboard := tgbotapi.NewOneTimeReplyKeyboard(rows...)
170
     keyboard := tgbotapi.NewOneTimeReplyKeyboard(rows...)
170
 
171
 
171
-    msg := tgbotapi.NewMessage(chat, "Select option below...")
172
+    msg := tgbotapi.NewMessage(chat, text)
172
     msg.ReplyToMessageID = message
173
     msg.ReplyToMessageID = message
173
     msg.ReplyMarkup = keyboard
174
     msg.ReplyMarkup = keyboard
174
     _, err := bot.Send(msg)
175
     _, err := bot.Send(msg)
231
 
232
 
232
     config.Registration = append(config.Registration, r)
233
     config.Registration = append(config.Registration, r)
233
     writeConfig()
234
     writeConfig()
235
+
236
+
237
+    token := mqttClient.Subscribe(topic, 0, onMessageReceived)
238
+    if token.Wait() && token.Error() != nil {
239
+        log.Printf("MQTT sub error: %v", token.Error())
240
+    }
241
+
234
     return nil
242
     return nil
235
 }
243
 }
236
 
244
 
242
 func unregister(name string) error {
250
 func unregister(name string) error {
243
     for reg := range config.Registration {
251
     for reg := range config.Registration {
244
         if name == config.Registration[reg].Name {
252
         if name == config.Registration[reg].Name {
253
+            token := mqttClient.Unsubscribe(config.Registration[reg].Topic)
254
+            if token.Wait() && token.Error() != nil {
255
+                log.Println("MQTT unsub error: %v", token.Error())
256
+            }
257
+
245
             config.Registration = remove(config.Registration, reg)
258
             config.Registration = remove(config.Registration, reg)
246
             writeConfig()
259
             writeConfig()
260
+
247
             return nil
261
             return nil
248
         }
262
         }
249
     }
263
     }
282
     return "unknown"
296
     return "unknown"
283
 }
297
 }
284
 
298
 
299
+func lastValueForCommand(name string) string {
300
+    ret := ""
301
+
302
+    for reg := range config.Registration {
303
+        if name == config.Registration[reg].Name {
304
+            if len(config.Registration[reg].lastValue) > 0 {
305
+                ret = "Current state: \""
306
+                ret += config.Registration[reg].lastValue
307
+                ret += "\"\n"
308
+            }
309
+            break
310
+        }
311
+    }
312
+
313
+    ret += "Select option below..."
314
+    return ret
315
+}
316
+
317
+func onMessageReceived(client mqtt.Client, message mqtt.Message) {
318
+    log.Printf("MQTT Rx: %s @ %s", message.Payload(), message.Topic())
319
+
320
+    for reg := range config.Registration {
321
+        if config.Registration[reg].Topic == message.Topic() {
322
+            config.Registration[reg].lastValue = string(message.Payload()[:])
323
+        }
324
+    }
325
+}
326
+
285
 func main() {
327
 func main() {
286
     err := readConfig()
328
     err := readConfig()
287
     if err != nil {
329
     if err != nil {
305
     opts.SetPassword(config.Mqtt.Pass)
347
     opts.SetPassword(config.Mqtt.Pass)
306
 
348
 
307
     mqttClient = mqtt.NewClient(opts)
349
     mqttClient = mqtt.NewClient(opts)
308
-    if token := mqttClient.Connect(); token.Wait() && token.Error() != nil {
350
+    token := mqttClient.Connect();
351
+    if token.Wait() && token.Error() != nil {
309
         log.Printf("MQTT error: %v", token.Error())
352
         log.Printf("MQTT error: %v", token.Error())
310
         os.Exit(1)
353
         os.Exit(1)
311
     }
354
     }
312
 
355
 
356
+    // Subscribe to registered topics
357
+    for reg := range config.Registration {
358
+        token := mqttClient.Subscribe(config.Registration[reg].Topic, 0, onMessageReceived)
359
+        if token.Wait() && token.Error() != nil {
360
+            log.Printf("MQTT sub error: %v", token.Error())
361
+        }
362
+    }
363
+
313
     // Initialize Telegram
364
     // Initialize Telegram
314
     bot, err = tgbotapi.NewBotAPI(config.Key)
365
     bot, err = tgbotapi.NewBotAPI(config.Key)
315
     if err != nil {
366
     if err != nil {
381
                                 reply = fmt.Sprintf("Error authorizing ID! %v", err)
432
                                 reply = fmt.Sprintf("Error authorizing ID! %v", err)
382
                             } else {
433
                             } else {
383
                                 reply = fmt.Sprintf("Ok, authorized %d.", id)
434
                                 reply = fmt.Sprintf("Ok, authorized %d.", id)
435
+
436
+                                // also notify user
437
+                                text := "You have now been authorized by the admin. Try /help for commands."
438
+                                sendMessage(text, id)
384
                             }
439
                             }
385
                         }
440
                         }
386
                     } else {
441
                     } else {
460
                         }
515
                         }
461
                     } else if isRegisteredCommand(update.Message.Text[1:]) {
516
                     } else if isRegisteredCommand(update.Message.Text[1:]) {
462
                         reply = ""
517
                         reply = ""
463
-                        sendKeyboardReply(update.Message.Text[1:], update.Message.Chat.ID, update.Message.MessageID)
518
+                        text := lastValueForCommand(update.Message.Text[1:])
519
+                        sendKeyboardReply(text, update.Message.Text[1:], update.Message.Chat.ID, update.Message.MessageID)
464
                     }
520
                     }
465
             }
521
             }
466
         } else {
522
         } else {
467
-            log.Printf("Message from unauthorized user. %s %d", update.Message.From.UserName, update.Message.From.ID)
468
-            notifyAdminAuthorization(update.Message.From.ID, update.Message.From.UserName)
523
+            // only request admin-auth when /start has been sent!
524
+            // this avoids most bot spam.
525
+            if update.Message.Text == "/start" {
526
+                log.Printf("Message from unauthorized user. %s %d", update.Message.From.UserName, update.Message.From.ID)
527
+                notifyAdminAuthorization(update.Message.From.ID, update.Message.From.UserName)
469
 
528
 
470
-            reply = "Sorry, you are not authorized. Administrator confirmation required."
529
+                reply = "Sorry, you are not authorized. Administrator confirmation required."
530
+            }
471
         }
531
         }
472
 
532
 
473
         // send a reply
533
         // send a reply

Loading…
Cancel
Save