Setup MQTT client proxy connection

This commit is contained in:
Garth Vander Houwen 2023-08-01 22:28:02 -07:00
parent 9c04add62a
commit a11d41c137
3 changed files with 220 additions and 0 deletions

View file

@ -121,6 +121,7 @@
DDCDC6CB29481FCC004C1DDA /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = DDCDC6CD29481FCC004C1DDA /* Localizable.strings */; };
DDCE4E2C2869F92900BE9F8F /* UserConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDCE4E2B2869F92900BE9F8F /* UserConfig.swift */; };
DDD3BBD5292D763200D609B3 /* MeshtasticTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD3BBD4292D763200D609B3 /* MeshtasticTests.swift */; };
DDD43FE32A78C8900083A3E9 /* MqttClientProxyManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD43FE22A78C8900083A3E9 /* MqttClientProxyManager.swift */; };
DDD6EEAF29BC024700383354 /* Firmware.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD6EEAE29BC024700383354 /* Firmware.swift */; };
DDD94A502845C8F5004A87A0 /* DateTimeText.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD94A4F2845C8F5004A87A0 /* DateTimeText.swift */; };
DDD9E4E4284B208E003777C5 /* UserEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD9E4E3284B208E003777C5 /* UserEntityExtension.swift */; };
@ -323,6 +324,7 @@
DDCDC6CE294821AD004C1DDA /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
DDCE4E2B2869F92900BE9F8F /* UserConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserConfig.swift; sourceTree = "<group>"; };
DDD3BBD4292D763200D609B3 /* MeshtasticTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeshtasticTests.swift; sourceTree = "<group>"; };
DDD43FE22A78C8900083A3E9 /* MqttClientProxyManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MqttClientProxyManager.swift; sourceTree = "<group>"; };
DDD6EEAE29BC024700383354 /* Firmware.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Firmware.swift; sourceTree = "<group>"; };
DDD94A4F2845C8F5004A87A0 /* DateTimeText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTimeText.swift; sourceTree = "<group>"; };
DDD9E4E3284B208E003777C5 /* UserEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserEntityExtension.swift; sourceTree = "<group>"; };
@ -710,6 +712,7 @@
DDC2E1A526CEB32B0042C5E4 /* Helpers */ = {
isa = PBXGroup;
children = (
DDD43FE12A78C86B0083A3E9 /* Mqtt */,
DDB75A122A0593CD006ED576 /* Map */,
DDAF8C5226EB1DF10058C060 /* BLEManager.swift */,
DDC2E1A626CEB3400042C5E4 /* LocationHelper.swift */,
@ -736,6 +739,14 @@
path = Persistence;
sourceTree = "<group>";
};
DDD43FE12A78C86B0083A3E9 /* Mqtt */ = {
isa = PBXGroup;
children = (
DDD43FE22A78C8900083A3E9 /* MqttClientProxyManager.swift */,
);
path = Mqtt;
sourceTree = "<group>";
};
DDDB443E29F79A9400EE2349 /* Extensions */ = {
isa = PBXGroup;
children = (
@ -1032,6 +1043,7 @@
DD3CC6C228EB9D4900FA9159 /* UpdateCoreData.swift in Sources */,
DDE0F7C5295F77B700B8AAB3 /* AppSettingsEnums.swift in Sources */,
DDB6ABE628B1406100384BA1 /* LoraConfigEnums.swift in Sources */,
DDD43FE32A78C8900083A3E9 /* MqttClientProxyManager.swift in Sources */,
DDDB444629F8A96500EE2349 /* Character.swift in Sources */,
DD23A50F26FD1B4400D9B90C /* PeripheralModel.swift in Sources */,
DDB6ABDB28B0AC6000384BA1 /* DistanceText.swift in Sources */,

View file

@ -3,6 +3,7 @@ import CoreData
import CoreBluetooth
import SwiftUI
import MapKit
import CocoaMQTT
// ---------------------------------------------------------------------------------------
// Meshtastic BLE Device Manager
@ -37,6 +38,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject {
var positionTimer: Timer?
var lastPosition: CLLocationCoordinate2D?
let emptyNodeNum: UInt32 = 4294967295
let mqttManager = MqttClientProxyManager.shared
/* Meshtastic Service Details */
var TORADIO_characteristic: CBCharacteristic!
var FROMRADIO_characteristic: CBCharacteristic!
@ -573,6 +575,22 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject {
RunLoop.current.add(positionTimer!, forMode: .common)
}
}
/// MQTT Client Proxy
if true {
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(connectedPeripheral.num))
do {
let fetchedNodeInfo = try context?.fetch(fetchNodeInfoRequest) as? [NodeInfoEntity] ?? []
if fetchedNodeInfo.count == 1 && fetchedNodeInfo[0].mqttConfig != nil {
//Subscribe to Mqtt Client Proxy if enabled
mqttManager.connectFromConfigSettings(config: fetchedNodeInfo[0].mqttConfig!)
}
} catch {
print("Failed to find a node info for the connected node")
}
}
return
}

View file

@ -0,0 +1,190 @@
//
// MQTTManager.swift
// Meshtastic
//
// Created by Garth Vander Houwen on 7/31/23.
//
import Foundation
import CocoaMQTT
class MqttClientProxyManager {
enum ConnectionStatus {
case connecting
case connected
case disconnecting
case disconnected
case error
case none
}
enum MqttQos: Int {
case atMostOnce = 0
case atLeastOnce = 1
case exactlyOnce = 2
}
static let shared = MqttClientProxyManager()
private static let defaultKeepAliveInterval: Int32 = 60
weak var delegate: CocoaMQTTDelegate?
var status = ConnectionStatus.none
var mqttClient: CocoaMQTT?
private init() {
}
func connectFromConfigSettings(config: MQTTConfigEntity) {
let defaultServerAddress = "mqtt.meshtastic.org"
let defaultServerPort = 1883
//let
var host = config.address
if host == nil || host!.isEmpty {
host = defaultServerAddress
}
if let host = host {
let port = defaultServerPort
let username = config.username
let password = config.password
connect(host: host, port: port, username: username, password: password, cleanSession: true)
}
}
func connect(host: String, port: Int, username: String?, password: String?, cleanSession: Bool) {
let clientId = "MeshtasticAppleMqttProxy-" + String(ProcessInfo().processIdentifier)
status = .connecting
mqttClient = CocoaMQTT(clientID: clientId, host: host, port: UInt16(port))
if let mqttClient = mqttClient {
mqttClient.username = username
mqttClient.password = password
mqttClient.keepAlive = 60
mqttClient.cleanSession = cleanSession
mqttClient.logLevel = .debug
mqttClient.willMessage = CocoaMQTTMessage(topic: "/will", string: "dieout")
mqttClient.autoReconnect = true
mqttClient.delegate = self
let success = mqttClient.connect()
if !success {
status = .error
}
} else {
status = .error
}
}
func subscribe(topic: String, qos: MqttQos) {
let qos = CocoaMQTTQoS(rawValue :UInt8(qos.rawValue))!
mqttClient?.subscribe(topic, qos: qos)
}
func unsubscribe(topic: String) {
mqttClient?.unsubscribe(topic)
}
func publish(message: String, topic: String, qos: MqttQos) {
let qos = CocoaMQTTQoS(rawValue :UInt8(qos.rawValue))!
mqttClient?.publish(topic, withString: message, qos: qos)
}
func disconnect() {
//MqttSettings.shared.isConnected = false
if let client = mqttClient {
status = .disconnecting
client.disconnect()
} else {
status = .disconnected
}
}
}
extension MqttClientProxyManager: CocoaMQTTDelegate {
func mqtt(_ mqtt: CocoaMQTT, didReceive trust: SecTrust, completionHandler: @escaping (Bool) -> Void) {
completionHandler(true)
}
func mqtt(_ mqtt: CocoaMQTT, didConnectAck ack: CocoaMQTTConnAck) {
print("didConnectAck: \(ack)")
if ack == .accept {
//delegate?.onMqttConnected()
// if let topic = mqttSettings.subscribeTopic, mqttSettings.isSubscribeEnabled {
// self.subscribe(topic: topic, qos: mqttSettings.subscribeQos)
// }
} else {
// Connection error
var errorDescription = "Unknown Error"
switch ack {
case .accept:
errorDescription = "No Error"
case .unacceptableProtocolVersion:
errorDescription = "Proto ver"
case .identifierRejected:
errorDescription = "Invalid Id"
case .serverUnavailable:
errorDescription = "Invalid Server"
case .badUsernameOrPassword:
errorDescription = "Invalid Credentials"
case .notAuthorized:
errorDescription = "Authorization Error"
default:
errorDescription = "Unknown Error"
}
print(errorDescription)
//delegate?.onMqttError(message: errorDescription)
//self.disconnect() // Stop reconnecting
//mqttSettings.isConnected = false // Disable automatic connect on start
}
self.status = ack == .accept ? ConnectionStatus.connected : ConnectionStatus.error // Set AFTER sending onMqttError (so the delegate can detect that was an error while stablishing connection)
}
func mqtt(_ mqtt: CocoaMQTT, didPublishMessage message: CocoaMQTTMessage, id: UInt16) {
print("didPublishMessage")
}
func mqtt(_ mqtt: CocoaMQTT, didPublishAck id: UInt16) {
print("didPublishAck")
}
func mqtt(_ mqtt: CocoaMQTT, didReceiveMessage message: CocoaMQTTMessage, id: UInt16) {
if let string = message.string {
print("didReceiveMessage: \(string) from topic: \(message.topic)")
} else {
print("didReceiveMessage but message is not defined")
}
}
func mqtt(_ mqtt: CocoaMQTT, didSubscribeTopics success: NSDictionary, failed: [String]) {
print("didSubscribeTopics: \(success.allKeys.count) topics. failed: \(failed.count) topics")
}
func mqtt(_ mqtt: CocoaMQTT, didUnsubscribeTopics topics: [String]) {
print("didUnsubscribeTopics: \(topics.joined(separator: ", "))")
}
func mqttDidPing(_ mqtt: CocoaMQTT) {
print("mqttDidPing")
}
func mqttDidReceivePong(_ mqtt: CocoaMQTT) {
print("mqttDidReceivePong")
}
func mqttDidDisconnect(_ mqtt: CocoaMQTT, withError err: Error?) {
print("mqttDidDisconnect")
}
}