Improve Home Assistant connection reliability

This commit is contained in:
2026-07-27 16:23:40 -07:00
parent b7ec774efd
commit f3341ee064
16 changed files with 1696 additions and 697 deletions
@@ -10,7 +10,7 @@ import Darwin
import Foundation
import UIKit
protocol SwitchesViewControllerDelegate: class
protocol SwitchesViewControllerDelegate: AnyObject
{
func switchesViewControllerDidToggleDevices(_ controller: SwitchesViewController, devices: [AnyDevice])
}
@@ -29,9 +29,8 @@ class SwitchesViewController: UIViewController,
fileprivate var _collectionView: UICollectionView = UICollectionView(frame: CGRect.zero,
collectionViewLayout: UICollectionViewFlowLayout())
fileprivate var _collectionViewDataSource: UICollectionViewDiffableDataSource<Int, Int>!
fileprivate var _currentDevicesHash: Int = 0
fileprivate var _collectionViewDataSource:
UICollectionViewDiffableDataSource<Int, ItemIdentifier>!
fileprivate let _label = UILabel(frame: .zero)
@@ -42,7 +41,7 @@ class SwitchesViewController: UIViewController,
static fileprivate let actionCellsSectionIdentifier = 0
static fileprivate let switchCellsSectionIdentifier = 1
fileprivate enum ActionCell: Int, CaseIterable
fileprivate enum ActionCell: Int, CaseIterable, Hashable
{
case allOn
case allOff
@@ -59,6 +58,12 @@ class SwitchesViewController: UIViewController,
static let count: Int = { return ActionCell.allCases.count }()
}
fileprivate enum ItemIdentifier: Hashable
{
case action(ActionCell)
case device(String)
}
public enum ActionCellLayout
{
@@ -85,8 +90,8 @@ class SwitchesViewController: UIViewController,
// Action cells
snapshot.appendItems([
SwitchesViewController.ActionCell.allOn.rawValue,
SwitchesViewController.ActionCell.allOff.rawValue
.action(.allOn),
.action(.allOff)
], toSection: SwitchesViewController.actionCellsSectionIdentifier)
_collectionViewDataSource.apply(snapshot, animatingDifferences: false)
@@ -158,7 +163,10 @@ class SwitchesViewController: UIViewController,
var snapshot = _collectionViewDataSource.snapshot()
snapshot.deleteItems(snapshot.itemIdentifiers(inSection: SwitchesViewController.switchCellsSectionIdentifier))
snapshot.appendItems(self.devices.map { $0.hashValue }, toSection: SwitchesViewController.switchCellsSectionIdentifier)
snapshot.appendItems(
self.devices.map { .device($0.serial) },
toSection: SwitchesViewController.switchCellsSectionIdentifier
)
snapshot.reloadSections([Self.actionCellsSectionIdentifier])
_collectionViewDataSource.apply(snapshot, animatingDifferences: false)
}
@@ -168,9 +176,14 @@ class SwitchesViewController: UIViewController,
{
var snapshot = _collectionViewDataSource.snapshot()
changedDevices.forEach { changedDevice in
if let existingDevice = (self.devices.first { $0.hashValue == changedDevice.hashValue }) {
if let existingDevice = self.devices.first(where: {
$0.serial == changedDevice.serial
}) {
existingDevice.state = changedDevice.state
snapshot.reloadItems([ existingDevice.hashValue ])
let identifier = ItemIdentifier.device(existingDevice.serial)
if snapshot.indexOfItem(identifier) != nil {
snapshot.reloadItems([identifier])
}
}
}
@@ -179,29 +192,36 @@ class SwitchesViewController: UIViewController,
// MARK: UICollectionView
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath, identifier: Int) -> UICollectionViewCell?
fileprivate func collectionView(
_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath,
identifier: ItemIdentifier
) -> UICollectionViewCell?
{
if (indexPath.section == SwitchesViewController.actionCellsSectionIdentifier) {
switch identifier {
case .action(let action):
let reuseID = SwitchesViewController.collectionViewActionCellReuseIdentifier
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseID, for: indexPath) as! WemoActionCellView
cell.textLabel.text = ActionCell(rawValue: identifier)?.name().uppercased()
cell.textLabel.text = action.name().uppercased()
cell.accessibilityIdentifier = "action.\(action.rawValue)"
cell.accessibilityLabel = action.name()
cell.enabled = (self.devices.count > 0)
return cell
} else if (indexPath.section == SwitchesViewController.switchCellsSectionIdentifier) {
case .device(let serial):
let reuseID = SwitchesViewController.collectionViewDeviceSwitchCellReuseIdentifier
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseID, for: indexPath) as! WemoDeviceCellView
if let device = (self.devices.first { $0.hashValue == identifier }) {
if let device = self.devices.first(where: { $0.serial == serial }) {
cell.deviceName = device.name
cell.toggled = (device.state == .on)
cell.ordinal = indexPath.row
cell.accessibilityIdentifier = "device.\(device.serial)"
}
return cell
}
return nil
}
func collectionView(_ collectionView: UICollectionView,
@@ -252,9 +272,12 @@ class SwitchesViewController: UIViewController,
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
{
if (indexPath.section == SwitchesViewController.actionCellsSectionIdentifier) {
let tappedActionCell = ActionCell(rawValue: indexPath.item)
guard let identifier = _collectionViewDataSource.itemIdentifier(for: indexPath) else {
return
}
switch identifier {
case .action(let tappedActionCell):
for cell in collectionView.visibleCells {
if collectionView.indexPath(for: cell)?.section == SwitchesViewController.switchCellsSectionIdentifier {
let switchCell = cell as! WemoDeviceCellView
@@ -272,13 +295,17 @@ class SwitchesViewController: UIViewController,
}
self.delegate?.switchesViewControllerDidToggleDevices(self, devices: self.devices)
} else if (indexPath.section == SwitchesViewController.switchCellsSectionIdentifier) {
let cell = collectionView.cellForItem(at: indexPath) as! WemoDeviceCellView
case .device(let serial):
guard
let cell = collectionView.cellForItem(at: indexPath) as? WemoDeviceCellView,
let device = self.devices.first(where: { $0.serial == serial })
else {
return
}
cell.toggled = !cell.toggled
let device = self.devices[indexPath.row]
device.state = (cell.toggled ? .on : .off)
self.delegate?.switchesViewControllerDidToggleDevices(self, devices: [device])
}
}