Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SecuritySystem - Show as Single Tile #125

Closed
kentnz opened this issue Jan 3, 2021 · 4 comments
Closed

SecuritySystem - Show as Single Tile #125

kentnz opened this issue Jan 3, 2021 · 4 comments

Comments

@kentnz
Copy link

kentnz commented Jan 3, 2021

I'm setting up a 'SecuritySystem' with 6 zones in it.

When I use the Apple HomeKit Accessory Simulator for the six zones, they appear as a single 'Tile' in the 'Home' app and there is an toggle to 'Show as Single Tile' or 'Show as Separate Tiles'.

I cannot figure out how to recreate this setup using HAP. They always appear as separate tiles and there is no option to 'Show as Single Tile'.

Does anyone know how to create it so that they can be a single 'Tile' ?

Note: I've tried using the same 'serialNumber', etc.

Thanks
Kent.


let zone1Info = Service.Info(name: "Name1", serialNumber: "A1801", manufacturer: "Linux", model: "A", firmwareRevision: "1")
let zone2Info = Service.Info(name: "Name2", serialNumber: "A1802", manufacturer: "Linux", model: "A", firmwareRevision: "1")
let zone3Info = Service.Info(name: "Name3", serialNumber: "A1803", manufacturer: "Linux", model: "A", firmwareRevision: "1")
let zone4Info = Service.Info(name: "Name4", serialNumber: "A1804", manufacturer: "Linux", model: "A", firmwareRevision: "1")
let zone5Info = Service.Info(name: "Name5", serialNumber: "A1805", manufacturer: "Linux", model: "A", firmwareRevision: "1")
let zone6Info = Service.Info(name: "Name6", serialNumber: "A1806", manufacturer: "Linux", model: "A", firmwareRevision: "1")
let zone1 = OfficeAlarmSystem(info: zone1Info, name: "Name1" )
let zone2 = OfficeAlarmSystem(info: zone2Info, name: "Name2" )
let zone3 = OfficeAlarmSystem(info: zone3Info, name: "Name3" )
let zone4 = OfficeAlarmSystem(info: zone4Info, name: "Name4" )
let zone5 = OfficeAlarmSystem(info: zone5Info, name: "Name5" )
let zone6 = OfficeAlarmSystem(info: zone6Info, name: "Name6" )

let device = Device(
bridgeInfo: bridgeInfo,
setupCode: setupCode,
storage: storage,
accessories: [
zone1,
zone2,
zone3,
zone4,
zone5,
zone6
]

@Bouke
Copy link
Owner

Bouke commented Jan 4, 2021

In the simulator I suppose you've created a single accessory with multiple services, which can be done using this package as well:

let securitySystem = Accessory(info: .init(name: "Multi-Zone", serialNumber: "A1803"),
                               type: .securitySystem,
                               services: [
                                Service.SecuritySystemBase(characteristics: [.name("Zone A")]),
                                Service.SecuritySystemBase(characteristics: [.name("Zone B")])
                               ])
let device = Device(
    bridgeInfo: Service.Info(name: "Bridge", serialNumber: "00001"),
    setupCode: "123-44-321",
    storage: storage,
    accessories: [
        securitySystem
    ])

To include the optional characteristics "status fault" and "status tampered", you have to explicitly add those during initialization:

Service.SecuritySystemBase(characteristics: [.name("Zone A"), .statusFault(), .statusTampered()])

@kentnz
Copy link
Author

kentnz commented Jan 5, 2021 via email

@Bouke
Copy link
Owner

Bouke commented Jan 5, 2021

statusFault and statusTempered are available on the SecuritySystemBase : Service:

public let statusFault: GenericCharacteristic<UInt8>?
public let statusTampered: GenericCharacteristic<UInt8>?
.

The default accessory HAP.Accessory.SecuritySystem assumes a single SecuritySystem service:

public let securitySystem = Service.SecuritySystem()
public init(info: Service.Info, additionalServices: [Service] = []) {
super.init(info: info, type: .securitySystem, services: [securitySystem] + additionalServices)
}

In your situation, you're better off not extending SecuritySystem(|Base), but directly from Accessory instead. That gives you the freedom to add as many services as you like. See my example where I create such an accessory in a functional style. The same is possible in a declarative style through inheritance, something like this (untested):

class OfficeAlarmSystem : HAP.Accessory {
    var zones: Service.SecuritySystemBase[]

    init(info: Service.Info) {
        zones = [
            Service.SecuritySystemBase(characteristics: [.name("Zone A"), .statusFault(), .statusTampered()]),
            Service.SecuritySystemBase(characteristics: [.name("Zone B")])
        ]
        super.init(info:info,
                   type: .securitySystem,
                   services: zones)
        
        zones[0].statusTampered.value = 1
    }
}

@kentnz
Copy link
Author

kentnz commented Jan 5, 2021

I've created the class (with a couple of modifications)

  1. var zones: [Service.SecuritySystemBase] <-- XCode tells me [ ]'s should be around the item
  2. zones[0].statusTampered?.value = 0 <-- XCode tells me I need the ?
class OfficeAlarmSystem : HAP.Accessory {
    var zones: [Service.SecuritySystemBase]

    init(info: Service.Info) {
        zones = [
            Service.SecuritySystemBase(characteristics: [.name("Zone 1"), .statusTampered()] ),
            Service.SecuritySystemBase(characteristics: [.name("Zone 2"), .statusTampered()] ),
            Service.SecuritySystemBase(characteristics: [.name("Zone 3"), .statusTampered()] ),
            Service.SecuritySystemBase(characteristics: [.name("Zone 4"), .statusTampered()] ),
            Service.SecuritySystemBase(characteristics: [.name("Zone 5"), .statusTampered()] ),
            Service.SecuritySystemBase(characteristics: [.name("Zone 6"), .statusTampered()] )
        ]
        super.init(info:info,
                   type: .securitySystem,
                   services: zones)
        
        zones[0].statusTampered?.value = 0
        zones[1].statusTampered?.value = 1
        zones[2].statusTampered?.value = 0
        zones[3].statusTampered?.value = 0
        zones[4].statusTampered?.value = 0
        zones[5].statusTampered?.value = 0
    }

    // ----------------------------------------------------------------------------------------------------------
    override func characteristic<T>(_ characteristic: GenericCharacteristic<T>, ofService service: Service, didChangeValue newValue: T?)
    {
        logger.info("[Office Alarm] Characteristic \(characteristic) did change: \(String(describing: newValue))")

    }

}

Then in 'Main.swift' I've created the accessory.

let officeAlarmInfo = Service.Info(name: "Office Alarm",    serialNumber: "A1804", manufacturer: "Linux", model: "Touch", firmwareRevision: "10001")
let officeAlarm = OfficeAlarmSystem(info: officeAlarmInfo )

This appears to be working - so now to make it actually do something 👍

Kent.

@Bouke Bouke closed this as completed Jan 5, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants