@@ -27,8 +27,12 @@ class GroupMenuItem: NSMenuItem, CharacteristicUpdatable, LocalChangeNotifiable
2727 private var deviceStates : [ UUID : Bool ] = [ : ]
2828 private var characteristicToService : [ UUID : String ] = [ : ] // characteristicId -> serviceId
2929
30+ // For blinds: track positions separately
31+ private var positionStates : [ UUID : Int ] = [ : ] // currentPositionId -> position
32+ private var targetPositionIds : [ UUID ] = [ ] // targetPositionIds for writing
33+
3034 var characteristicIdentifiers : [ UUID ] {
31- return Array ( deviceStates. keys)
35+ return Array ( deviceStates. keys) + Array ( positionStates . keys )
3236 }
3337
3438 init ( group: DeviceGroup , menuData: MenuData , bridge: Mac2iOS ? ) {
@@ -84,14 +88,23 @@ class GroupMenuItem: NSMenuItem, CharacteristicUpdatable, LocalChangeNotifiable
8488 private func initializeDeviceStates( ) {
8589 let services = group. resolveServices ( in: menuData)
8690 for service in services {
87- // For power-based devices (lights, switches, etc.)
88- if let idString = service. powerStateId, let id = UUID ( uuidString: idString) {
89- let isOn = bridge? . getCharacteristicValue ( identifier: id) as? Bool ?? false
90- deviceStates [ id] = isOn
91+ // For blinds: track position (start at 0, will update from characteristic updates)
92+ if service. serviceType == ServiceTypes . windowCovering {
93+ if let currentIdString = service. currentPositionId,
94+ let currentId = UUID ( uuidString: currentIdString) {
95+ positionStates [ currentId] = 0
96+ }
97+ if let targetIdString = service. targetPositionId,
98+ let targetId = UUID ( uuidString: targetIdString) {
99+ targetPositionIds. append ( targetId)
100+ }
101+ }
102+ // For power-based devices (lights, switches, etc.) - start OFF, will update from characteristic updates
103+ else if let idString = service. powerStateId, let id = UUID ( uuidString: idString) {
104+ deviceStates [ id] = false
91105 characteristicToService [ id] = service. uniqueIdentifier
92106 } else if let idString = service. activeId, let id = UUID ( uuidString: idString) {
93- let value = bridge? . getCharacteristicValue ( identifier: id) as? Int ?? 0
94- deviceStates [ id] = value != 0
107+ deviceStates [ id] = false
95108 characteristicToService [ id] = service. uniqueIdentifier
96109 }
97110 }
@@ -107,7 +120,8 @@ class GroupMenuItem: NSMenuItem, CharacteristicUpdatable, LocalChangeNotifiable
107120
108121 let slider = ModernSlider ( minValue: 0 , maxValue: 100 )
109122 slider. frame = NSRect ( x: sliderX, y: sliderY, width: sliderWidth, height: 12 )
110- slider. doubleValue = 0
123+ slider. doubleValue = 0 // Start at 0, will update from characteristic updates
124+ slider. progressTintColor = DS . Colors. sliderBlind
111125 slider. isContinuous = false
112126 slider. target = self
113127 slider. action = #selector( sliderChanged ( _: ) )
@@ -125,6 +139,7 @@ class GroupMenuItem: NSMenuItem, CharacteristicUpdatable, LocalChangeNotifiable
125139
126140 let toggle = ToggleSwitch ( )
127141 toggle. frame = NSRect ( x: switchX, y: switchY, width: DS . ControlSize. switchWidth, height: DS . ControlSize. switchHeight)
142+ toggle. setOn ( false , animated: false ) // Start OFF, will update from bridge values
128143 toggle. target = self
129144 toggle. action = #selector( toggleChanged ( _: ) )
130145 containerView. addSubview ( toggle)
@@ -138,7 +153,19 @@ class GroupMenuItem: NSMenuItem, CharacteristicUpdatable, LocalChangeNotifiable
138153
139154 // Called when characteristic values change
140155 func updateValue( for characteristicId: UUID , value: Any , isLocalChange: Bool ) {
141- // Update our local state if this characteristic belongs to us
156+ // Update position state for blinds
157+ if positionStates. keys. contains ( characteristicId) {
158+ if let pos = ValueConversion . toInt ( value) {
159+ positionStates [ characteristicId] = pos
160+ // Update slider with average position
161+ let avgPosition = positionStates. values. reduce ( 0 , + ) / positionStates. count
162+ positionSlider? . doubleValue = Double ( avgPosition)
163+ updateBlindsIcon ( position: avgPosition)
164+ }
165+ return
166+ }
167+
168+ // Update power state for other devices
142169 if deviceStates. keys. contains ( characteristicId) {
143170 if let boolValue = ValueConversion . toBool ( value) {
144171 deviceStates [ characteristicId] = boolValue
@@ -208,16 +235,25 @@ class GroupMenuItem: NSMenuItem, CharacteristicUpdatable, LocalChangeNotifiable
208235 let services = group. resolveServices ( in: menuData)
209236 guard let bridge = bridge else { return }
210237
238+ // Update local position states and notify
239+ for (currentId, _) in positionStates {
240+ positionStates [ currentId] = position
241+ notifyLocalChange ( characteristicId: currentId, value: position)
242+ }
243+
244+ // Write to all target positions
211245 for service in services {
212246 if let idString = service. targetPositionId, let id = UUID ( uuidString: idString) {
213247 bridge. writeCharacteristic ( identifier: id, value: position)
214- notifyLocalChange ( characteristicId: id, value: position)
215248 }
216249 }
217250
218- // Update icon
219- let isOpen = position > 50
251+ updateBlindsIcon ( position: position)
252+ }
253+
254+ private func updateBlindsIcon( position: Int ) {
255+ let isOpen = position > 0
220256 iconView. image = NSImage ( systemSymbolName: isOpen ? " blinds.horizontal.open " : " blinds.horizontal.closed " , accessibilityDescription: nil )
221- iconView. contentTintColor = isOpen ? DS . Colors. success : DS . Colors. mutedForeground
257+ iconView. contentTintColor = isOpen ? DS . Colors. info : DS . Colors. mutedForeground
222258 }
223259}
0 commit comments