選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 
 

71 行
2.0 KiB

  1. package bridge
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "log/slog"
  7. "strings"
  8. "time"
  9. "github.com/AFASystems/presence/internal/pkg/common/appcontext"
  10. "github.com/AFASystems/presence/internal/pkg/kafkaclient"
  11. "github.com/AFASystems/presence/internal/pkg/model"
  12. "github.com/segmentio/kafka-go"
  13. )
  14. // HandleMQTTMessage processes an MQTT message: parses JSON array of RawReading or CSV.
  15. // For JSON, converts each reading to BeaconAdvertisement and writes to the writer if MAC is in lookup.
  16. // Hostname is derived from topic (e.g. "publish_out/gateway1" -> "gateway1"). Safe if topic has no "/".
  17. func HandleMQTTMessage(topic string, payload []byte, appState *appcontext.AppState, writer *kafka.Writer) {
  18. parts := strings.SplitN(topic, "/", 2)
  19. hostname := ""
  20. if len(parts) >= 2 {
  21. hostname = parts[1]
  22. }
  23. msgStr := string(payload)
  24. if strings.HasPrefix(msgStr, "[") {
  25. var readings []model.RawReading
  26. if err := json.Unmarshal(payload, &readings); err != nil {
  27. slog.Error("parsing MQTT JSON", "err", err, "topic", topic)
  28. return
  29. }
  30. for _, reading := range readings {
  31. if reading.Type == "Gateway" {
  32. continue
  33. }
  34. id, ok := appState.BeaconExists(reading.MAC)
  35. if !ok {
  36. continue
  37. }
  38. fmt.Println("beacon found: ", id)
  39. adv := appcontext.BeaconAdvertisement{
  40. ID: id,
  41. Hostname: hostname,
  42. MAC: reading.MAC,
  43. RSSI: int64(reading.RSSI),
  44. Data: reading.RawData,
  45. }
  46. encoded, err := json.Marshal(adv)
  47. if err != nil {
  48. slog.Error("marshaling beacon advertisement", "err", err)
  49. break
  50. }
  51. if err := kafkaclient.Write(context.Background(), writer, kafka.Message{Value: encoded}); err != nil {
  52. slog.Error("writing to Kafka", "err", err)
  53. time.Sleep(1 * time.Second)
  54. break
  55. }
  56. }
  57. return
  58. }
  59. // CSV format: validate minimum fields (e.g. 6 columns); full parsing can be added later
  60. s := strings.Split(msgStr, ",")
  61. if len(s) < 6 {
  62. slog.Error("invalid CSV MQTT message", "topic", topic, "message", msgStr)
  63. return
  64. }
  65. slog.Debug("CSV MQTT message received", "topic", topic, "fields", len(s))
  66. }