brutella / hc

hc is a lightweight framework to develop HomeKit accessories in Go.
Apache License 2.0
1.74k stars 189 forks source link

Persistent storage examples #153

Closed maaraneasi closed 4 years ago

maaraneasi commented 4 years ago

Hey! I have a very noob question (I am almost ashamed to ask) - how do I configure persistent storage of the accessory items? Currently, I am creating the accessory items and the bridge on every start of the program what is not optimal at all, because it means I need to re-add the bridge in the phone app on every restart of the program (because when restarting the app basically recreates all the accessories). I get there is the directory storing the entity file etc., but what is the proper approach for storing all the individual bulbs etc. and passing all these stored items plus the bridge to the transport on its startup? Are there any built-in functions I could use for storing and recalling accessories? I pass the bridge and a slice of bulbs to the transport based on another file I have what means that these are already "present" in the app in form of a slice or whatever and I struggle to find the right moment where (and how) to dump these objects to a file and finding the proper way of loading them again. Should I simply dump each accessory before adding it to the final slice (the slice that goes to the transport) to a separate file?

Thanks!!

brutella commented 4 years ago

It's pretty simple. The library automatically creates a persistent storage once you create an ip transport – see the header documentation of NewIPTransport().

If not specified otherwise in Config.StoragePath, the folder name (where all data is persistently stored) is the same as the accessory name.

maaraneasi commented 4 years ago

Hey Matthias!

If not specified otherwise in Config.StoragePath, the folder name (where all data is persistently stored) is the same as the accessory name.

Yeah, but his directory seems to be storing only the bridge - what I am struggling with is storing all the lights the same way so they don't get re-created. I am calling the transport like this t, err := hc.NewIPTransport(hc.Config{Pin: "12345678", Port: "36060", StoragePath: globalDatadir}, brAcc.Accessory, accessories...) and the directory is set to "data/". In that dir, I have:

maara@maaraBook  ~│D│D│p│h│data  ⎇ persistent  ll
.rw-r--r-- 191 maara  6 Dec 10:20 45333a41373a42303a30463a33353a3834.entity
.rw-r--r--  16 maara  6 Dec 12:34 configHash
.rw-r--r--  17 maara  6 Dec 12:34 uuid
.rw-r--r--   1 maara  6 Dec 12:34 version

Does this mean that the bridge (created in brAcc.Accessory) and all 30 lightbulbs (slice accessories aka accessories = append(accessories, light.Accessory)) are all stored here? I mean, there are really no special steps I need to take in order to store each of the light.Accessory so I can recall them on the next start? Do I need to tell the transport to reuse the items stored in this dir? - seems I always need to provide at least one accessory to this function. Also, the bridge is an object of accessory.NewLightbulb(*bridgeAccInfo) what means that the bridge gets created on each start so I assume that any data related the bridge stored in the storage dir gets overwritten anyway. (I am sorry if these questions are a bit dumb but I really can't tell based only on the docpage :-( )

brutella commented 4 years ago

The database doesn't contain the accessories itself. The accessories are created at runtime. You only have to make sure that the list of accessories, which are added to the ip transport, stays the same.

maaraneasi commented 4 years ago

You only have to make sure that the list of accessories, which are added to the ip transport, stays the same.

That's exactly what I am after! - I thought that the individual device are being saved as well and that I need to handle them separately... I changed my code so when it's building the final accessory slice, the order in which the lightbulbs are being added is always the same (by sorting the map I am loading the bulbs from) and it looks ok. Thanks for the heads up!

One last question - and I am not sure this is worth a new ticket - for an unknown after every new initialization of the bridge, one of the lights turns into an "unsupported" device, its icon turns into an icon of a house in the stock app (and into a grey rectangle with 4 dots in your app) and I can't control this device. Any idea why is this happening? - this device is no different from other devices and the device is picked by random. Is this the HC stack that changes the accessory type for some reason or the phone app that gets somehow confused?

brutella commented 4 years ago

Check if any property of an accessory, service or characteristic is invalid. First enable verbose logging via log.Debug.Enable() and check the logs for the json string, which contains the accessories, services and characteristics. Compare the json string between multiple launched of your project using a diff tool.

brutella commented 4 years ago

Is this still an issue?

maaraneasi commented 4 years ago

Yeah I am still having the issue where one of the accessories is being converted to an incorrect accessory type for some reason and I am not able to figure this out - I tried dump the characteristics but I didn't find anything of interest what would explain the issue. I must say that I didn't have much time to look into recently but I am planning to rewrite the app and add the persistent ID's so I might be able to find some more clues...

brutella commented 4 years ago

Ok, please re-open the issue if you still experience this problem when using explicit ids.