External notifications

This commit is contained in:
Garth Vander Houwen 2022-07-02 12:18:20 -07:00
parent bdc36610e6
commit 3c9f7718a6
5 changed files with 218 additions and 19 deletions

View file

@ -1129,6 +1129,66 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
return false
}
public func saveCannedMessageModuleConfig(config: ModuleConfig.CannedMessageConfig, fromUser: UserEntity, toUser: UserEntity, wantResponse: Bool) -> Int64 {
var newMessageId: Int64 = 0
var adminPacket = AdminMessage()
adminPacket.setModuleConfig.cannedMessage = config
var meshPacket: MeshPacket = MeshPacket()
meshPacket.to = UInt32(toUser.num)
meshPacket.from = 0 //UInt32(fromUser.num)
meshPacket.id = UInt32.random(in: UInt32(UInt8.max)..<UInt32.max)
meshPacket.priority = MeshPacket.Priority.reliable
meshPacket.wantAck = wantResponse
var dataMessage = DataMessage()
dataMessage.payload = try! adminPacket.serializedData()
dataMessage.portnum = PortNum.adminApp
meshPacket.decoded = dataMessage
var toRadio: ToRadio!
toRadio = ToRadio()
toRadio.packet = meshPacket
let binaryData: Data = try! toRadio.serializedData()
if connectedPeripheral!.peripheral.state == CBPeripheralState.connected {
let newMessage = MessageEntity(context: context!)
newMessage.messageId = Int64(UInt32.random(in: UInt32(UInt8.max)..<UInt32.max))
newMessageId = newMessage.messageId
newMessage.messageTimestamp = Int32(Date().timeIntervalSince1970)
newMessage.receivedACK = false
newMessage.direction = "OUT"
newMessage.admin = true
newMessage.fromUser = fromUser
newMessage.toUser = toUser
newMessage.messagePayload = try! dataMessage.jsonString()
do {
try context!.save()
if meshLoggingEnabled { MeshLogger.log("💾 Saved a new Canned Message Module Config Admin Message for node number: \(String(toUser.num))") }
connectedPeripheral.peripheral.writeValue(binaryData, for: TORADIO_characteristic, type: .withResponse)
} catch {
context!.rollback()
let nsError = error as NSError
print("💥 Error Inserting New Core Data MessageEntity: \(nsError)")
}
}
return newMessageId
}
public func saveRangeTestModuleConfig(config: ModuleConfig.RangeTestConfig, fromUser: UserEntity, toUser: UserEntity, wantResponse: Bool) -> Int64 {
var newMessageId: Int64 = 0

View file

@ -335,7 +335,7 @@ func moduleConfig (config: ModuleConfig, meshlogging: Bool, context:NSManagedObj
var isDefault = false
if (try! config.serial.jsonString()) == "{}" {
if (try! config.cannedMessage.jsonString()) == "{}" {
isDefault = true
print("🥫 Default Canned Message Module config")
@ -347,7 +347,7 @@ func moduleConfig (config: ModuleConfig, meshlogging: Bool, context:NSManagedObj
do {
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
// Found a node, save Device Config
// Found a node, save Canned Message Config
if !fetchedNode.isEmpty {
if fetchedNode[0].cannedMessageConfig == nil {
@ -432,6 +432,93 @@ func moduleConfig (config: ModuleConfig, meshlogging: Bool, context:NSManagedObj
}
}
if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.externalNotification(config.externalNotification) {
var isDefault = false
if (try! config.externalNotification.jsonString()) == "{}" {
isDefault = true
print("🚨 Default External Notifiation Module config")
}
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
do {
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
// Found a node, save External Notificaitone Config
if !fetchedNode.isEmpty {
if fetchedNode[0].externalNotificationConfig == nil {
let newExternalNotificationConfig = ExternalNotificationConfigEntity(context: context)
if isDefault {
newExternalNotificationConfig.enabled = false
newExternalNotificationConfig.alertBell = false
newExternalNotificationConfig.alertMessage = false
newExternalNotificationConfig.active = false
newExternalNotificationConfig.output = 0
newExternalNotificationConfig.outputMilliseconds = 0
} else {
newExternalNotificationConfig.enabled = config.externalNotification.enabled
newExternalNotificationConfig.alertBell = config.externalNotification.alertBell
newExternalNotificationConfig.alertMessage = config.externalNotification.alertMessage
newExternalNotificationConfig.active = config.externalNotification.active
newExternalNotificationConfig.output = Int32(config.externalNotification.output)
newExternalNotificationConfig.outputMilliseconds = Int32(config.externalNotification.outputMs)
}
fetchedNode[0].externalNotificationConfig = newExternalNotificationConfig
} else {
if isDefault {
fetchedNode[0].externalNotificationConfig?.enabled = false
fetchedNode[0].externalNotificationConfig?.alertBell = false
fetchedNode[0].externalNotificationConfig?.alertMessage = false
fetchedNode[0].externalNotificationConfig?.active = false
fetchedNode[0].externalNotificationConfig?.output = 0
fetchedNode[0].externalNotificationConfig?.outputMilliseconds = 0
} else {
fetchedNode[0].externalNotificationConfig?.enabled = config.externalNotification.enabled
fetchedNode[0].externalNotificationConfig?.alertBell = config.externalNotification.alertBell
fetchedNode[0].externalNotificationConfig?.alertMessage = config.externalNotification.alertMessage
fetchedNode[0].externalNotificationConfig?.active = config.externalNotification.active
fetchedNode[0].externalNotificationConfig?.output = Int32(config.externalNotification.output)
fetchedNode[0].externalNotificationConfig?.outputMilliseconds = Int32(config.externalNotification.outputMs)
}
}
do {
try context.save()
if meshlogging { MeshLogger.log("💾 Updated External Notification Module Config for node number: \(String(nodeNum))") }
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Updating Core Data ExternalNotificationConfigEntity: \(nsError)")
}
}
} catch {
}
}
if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.rangeTest(config.rangeTest) {
var isDefault = false

View file

@ -28,6 +28,16 @@
<attribute name="screenOnSeconds" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="displayConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="displayConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="ExternalNotificationConfigEntity" representedClassName="ExternalNotificationConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="active" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="alertBell" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="alertMessage" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="num" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="output" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="outputMilliseconds" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="externalNotificationConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="externalNotificationConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="LoRaConfigEntity" representedClassName="LoRaConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="hopLimit" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="modemPreset" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
@ -85,6 +95,7 @@
<relationship name="cannedMessageConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="CannedMessageConfigEntity" inverseName="cannedMessagesConfigNode" inverseEntity="CannedMessageConfigEntity"/>
<relationship name="deviceConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="DeviceConfigEntity" inverseName="deviceConfigNode" inverseEntity="DeviceConfigEntity"/>
<relationship name="displayConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="DisplayConfigEntity" inverseName="displayConfigNode" inverseEntity="DisplayConfigEntity"/>
<relationship name="externalNotificationConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="ExternalNotificationConfigEntity" inverseName="externalNotificationConfigNode" inverseEntity="ExternalNotificationConfigEntity"/>
<relationship name="loRaConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="LoRaConfigEntity" inverseName="loRaConfigNode" inverseEntity="LoRaConfigEntity"/>
<relationship name="myInfo" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MyInfoEntity" inverseName="myInfoNode" inverseEntity="MyInfoEntity"/>
<relationship name="positionConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="PositionConfigEntity" inverseName="positionConfigNode" inverseEntity="PositionConfigEntity"/>
@ -170,12 +181,13 @@
<element name="LoRaConfigEntity" positionX="45" positionY="144" width="128" height="104"/>
<element name="MessageEntity" positionX="-36" positionY="63" width="128" height="230"/>
<element name="MyInfoEntity" positionX="-18" positionY="81" width="128" height="209"/>
<element name="NodeInfoEntity" positionX="-63" positionY="-18" width="128" height="269"/>
<element name="NodeInfoEntity" positionX="-63" positionY="-18" width="128" height="284"/>
<element name="PositionConfigEntity" positionX="63" positionY="162" width="128" height="149"/>
<element name="PositionEntity" positionX="-54" positionY="54" width="128" height="119"/>
<element name="RangeTestConfigEntity" positionX="72" positionY="171" width="128" height="104"/>
<element name="TelemetryEntity" positionX="160" positionY="192" width="128" height="194"/>
<element name="UserEntity" positionX="0" positionY="144" width="128" height="200"/>
<element name="SerialConfigEntity" positionX="54" positionY="153" width="128" height="164"/>
<element name="ExternalNotificationConfigEntity" positionX="63" positionY="162" width="128" height="149"/>
</elements>
</model>

View file

@ -68,6 +68,28 @@ enum InputEventChars: Int, CaseIterable, Identifiable {
}
}
}
func protoEnumValue() -> ModuleConfig.CannedMessageConfig.InputEventChar {
switch self {
case .keyNone:
return ModuleConfig.CannedMessageConfig.InputEventChar.keyNone
case .keyUp:
return ModuleConfig.CannedMessageConfig.InputEventChar.keyUp
case .keyDown:
return ModuleConfig.CannedMessageConfig.InputEventChar.keyDown
case .keyLeft:
return ModuleConfig.CannedMessageConfig.InputEventChar.keyLeft
case .keyRight:
return ModuleConfig.CannedMessageConfig.InputEventChar.keyRight
case .keySelect:
return ModuleConfig.CannedMessageConfig.InputEventChar.keySelect
case .keyBack:
return ModuleConfig.CannedMessageConfig.InputEventChar.keyBack
case .keyCancel:
return ModuleConfig.CannedMessageConfig.InputEventChar.keyCancel
}
}
}
struct CannedMessagesConfig: View {
@ -282,16 +304,18 @@ struct CannedMessagesConfig: View {
cmc.inputbrokerPinA = UInt32(inputbrokerPinA)
cmc.inputbrokerPinB = UInt32(inputbrokerPinB)
cmc.inputbrokerPinPress = UInt32(inputbrokerPinPress)
cmc.inputbrokerEventCw = InputEventChars(rawValue: inputbrokerEventCw)!.protoEnumValue()
cmc.inputbrokerEventCcw = InputEventChars(rawValue: inputbrokerEventCcw)!.protoEnumValue()
cmc.inputbrokerEventPress = InputEventChars(rawValue: inputbrokerEventPress)!.protoEnumValue()
//if bleManager.saveRangeTestModuleConfig(config: rtc, destNum: bleManager.connectedPeripheral.num, wantResponse: false) {
let adminMessageId = bleManager.saveCannedMessageModuleConfig(config: cmc, fromUser: node.user!, toUser: node.user!, wantResponse: true)
if adminMessageId > 0 {
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
hasChanges = false
//} else {
//}
}
}
}
@ -308,6 +332,7 @@ struct CannedMessagesConfig: View {
self.bleManager.context = context
self.enabled = node.cannedMessageConfig?.enabled ?? false
self.sendBell = node.cannedMessageConfig?.sendBell ?? false
self.rotary1Enabled = node.cannedMessageConfig?.rotary1Enabled ?? false
self.updown1Enabled = node.cannedMessageConfig?.updown1Enabled ?? false
self.inputbrokerPinA = Int(node.cannedMessageConfig?.inputbrokerPinA ?? 0)
@ -336,17 +361,35 @@ struct CannedMessagesConfig: View {
}
.onChange(of: enabled) { newEnabled in
//if newEnabled != node.cannedMessagesConfig!.enabled {
hasChanges = true
//}
if newEnabled != node.cannedMessageConfig!.enabled { hasChanges = true }
}
.onChange(of: sendBell) { newBell in
//if newBell != node.rangeTestConfig!.save {
hasChanges = true
//}
if newBell != node.cannedMessageConfig!.sendBell { hasChanges = true }
}
.onChange(of: inputbrokerPinA) { newPinA in
if newPinA != node.cannedMessageConfig!.inputbrokerPinA { hasChanges = true }
}
.onChange(of: inputbrokerPinB) { newPinB in
if newPinB != node.cannedMessageConfig!.inputbrokerPinB { hasChanges = true }
}
.onChange(of: inputbrokerPinPress) { newPinPress in
if newPinPress != node.cannedMessageConfig!.inputbrokerPinPress { hasChanges = true }
}
.onChange(of: inputbrokerEventCw) { newKeyA in
if newKeyA != node.cannedMessageConfig!.inputbrokerEventCw { hasChanges = true }
}
.onChange(of: inputbrokerEventCcw) { newKeyB in
if newKeyB != node.cannedMessageConfig!.inputbrokerEventCcw { hasChanges = true }
}
.onChange(of: inputbrokerEventPress) { newKeyPress in
if newKeyPress != node.cannedMessageConfig!.inputbrokerEventPress { hasChanges = true }
}
.navigationViewStyle(StackNavigationViewStyle())
}

View file

@ -63,9 +63,6 @@ struct ExternalNotificationConfig: View {
@State var active = false
@State var output = 0
@State var outputMilliseconds = 0
var body: some View {