mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
External notifications
This commit is contained in:
parent
bdc36610e6
commit
3c9f7718a6
5 changed files with 218 additions and 19 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,9 +63,6 @@ struct ExternalNotificationConfig: View {
|
|||
@State var active = false
|
||||
@State var output = 0
|
||||
@State var outputMilliseconds = 0
|
||||
|
||||
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue