├── .gitignore
├── Cartfile
├── Cartfile.private
├── Cartfile.resolved
├── Info-macOS.plist
├── LICENSE
├── README.md
├── Sources
├── Base
│ ├── BridgeAccessConfig.swift
│ ├── BridgeResourceModels
│ │ ├── AppData.swift
│ │ ├── Backup.swift
│ │ ├── BridgeConfiguration.swift
│ │ ├── BridgeResource.swift
│ │ ├── Error.swift
│ │ ├── Group.swift
│ │ ├── Light.swift
│ │ ├── LightState.swift
│ │ ├── PortalState.swift
│ │ ├── Rule
│ │ │ ├── Rule.swift
│ │ │ ├── RuleAction.swift
│ │ │ └── RuleCondition.swift
│ │ ├── Scene.swift
│ │ ├── Schedule
│ │ │ ├── Schedule.swift
│ │ │ └── ScheduleCommand.swift
│ │ ├── Sensors
│ │ │ ├── DaylightSensor
│ │ │ │ ├── DaylightSensor.swift
│ │ │ │ ├── DaylightSensorConfig.swift
│ │ │ │ └── DaylightSensorState.swift
│ │ │ ├── GenericFlagSensor
│ │ │ │ ├── GenericFlagSensor.swift
│ │ │ │ ├── GenericFlagSensorConfig.swift
│ │ │ │ └── GenericFlagSensorState.swift
│ │ │ ├── GenericStatusSensor
│ │ │ │ ├── GenericStatusSensor.swift
│ │ │ │ ├── GenericStatusSensorConfig.swift
│ │ │ │ └── GenericStatusSensorState.swift
│ │ │ ├── HumiditySensor
│ │ │ │ ├── HumiditySensor.swift
│ │ │ │ ├── HumiditySensorConfig.swift
│ │ │ │ └── HumiditySensorState.swift
│ │ │ ├── LightLevelSensor
│ │ │ │ ├── LightLevelSensor.swift
│ │ │ │ ├── LightLevelSensorConfig.swift
│ │ │ │ └── LightLevelSensorState.swift
│ │ │ ├── OpenCloseSensor
│ │ │ │ ├── OpenCloseSensor.swift
│ │ │ │ ├── OpenCloseSensorConfig.swift
│ │ │ │ └── OpenCloseSensorState.swift
│ │ │ ├── PresenceSensor
│ │ │ │ ├── PresenceSensor.swift
│ │ │ │ ├── PresenceSensorConfig.swift
│ │ │ │ └── PresenceSensorState.swift
│ │ │ ├── Sensor.swift
│ │ │ ├── SensorConfig.swift
│ │ │ ├── SensorState.swift
│ │ │ ├── SwitchSensor
│ │ │ │ ├── SwitchSensor.swift
│ │ │ │ ├── SwitchSensorConfig.swift
│ │ │ │ └── SwitchSensorState.swift
│ │ │ └── TemperatureSensor
│ │ │ │ ├── TemperatureSensor.swift
│ │ │ │ ├── TemperatureSensorConfig.swift
│ │ │ │ └── TemperatureSensorState.swift
│ │ ├── SoftwareUpdateStatus.swift
│ │ ├── SoftwareUpdateStatusDeviceTypes.swift
│ │ └── WhitelistEntry.swift
│ ├── BridgeResourcesCache.swift
│ ├── BridgeSendAPI.swift
│ ├── Dictionary+Extension.swift
│ ├── HeartbeatManager.swift
│ ├── Logger
│ │ └── LoggerConfig.swift
│ ├── NSDateFormatter+Extension.swift
│ ├── ReplaceMe.swift
│ ├── ResourceAPI.swift
│ ├── ResourceCacheHeartbeatProcessor.swift
│ ├── SwiftyHue.swift
│ ├── TestRequester.swift
│ └── Utilities.swift
├── BridgeServices
│ ├── BridgeAuthenticator
│ │ ├── BridgeAuthenticator.swift
│ │ └── BridgeAuthenticatorDelegate.swift
│ └── BridgeFinder
│ │ ├── BridgeFinder.swift
│ │ ├── BridgeFinderDelegate.swift
│ │ ├── HueBridge.swift
│ │ ├── HueBridgeIcon.swift
│ │ ├── Scanner
│ │ ├── IPScanner.swift
│ │ ├── NUPNPScanner.swift
│ │ ├── SSDPScanner.swift
│ │ ├── Scanner.swift
│ │ └── ScannerDelegate.swift
│ │ └── Validator
│ │ ├── BridgeResultParser.swift
│ │ └── BridgeValidator.swift
├── Info-iOS.plist
├── Info-tvOS.plist
├── Info-watchOS.plist
└── SwiftyHue.h
├── SwiftyHue Example Watch Extension
├── Assets.xcassets
│ └── README__ignoredByTemplate__
├── ExtensionDelegate.swift
├── Info.plist
└── InterfaceController.swift
├── SwiftyHue Example Watch
├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Base.lproj
│ └── Interface.storyboard
└── Info.plist
├── SwiftyHue Example tvOS
├── AppDelegate.swift
├── Assets.xcassets
│ ├── App Icon & Top Shelf Image.brandassets
│ │ ├── App Icon - Large.imagestack
│ │ │ ├── Back.imagestacklayer
│ │ │ │ ├── Content.imageset
│ │ │ │ │ └── Contents.json
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ ├── Front.imagestacklayer
│ │ │ │ ├── Content.imageset
│ │ │ │ │ └── Contents.json
│ │ │ │ └── Contents.json
│ │ │ └── Middle.imagestacklayer
│ │ │ │ ├── Content.imageset
│ │ │ │ └── Contents.json
│ │ │ │ └── Contents.json
│ │ ├── App Icon - Small.imagestack
│ │ │ ├── Back.imagestacklayer
│ │ │ │ ├── Content.imageset
│ │ │ │ │ └── Contents.json
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ ├── Front.imagestacklayer
│ │ │ │ ├── Content.imageset
│ │ │ │ │ └── Contents.json
│ │ │ │ └── Contents.json
│ │ │ └── Middle.imagestacklayer
│ │ │ │ ├── Content.imageset
│ │ │ │ └── Contents.json
│ │ │ │ └── Contents.json
│ │ ├── Contents.json
│ │ └── Top Shelf Image.imageset
│ │ │ └── Contents.json
│ ├── Contents.json
│ ├── LaunchImage.launchimage
│ │ └── Contents.json
│ ├── first.imageset
│ │ ├── Contents.json
│ │ └── first.pdf
│ └── second.imageset
│ │ ├── Contents.json
│ │ └── second.pdf
├── Base.lproj
│ └── Main.storyboard
├── FirstViewController.swift
├── Info.plist
└── SecondViewController.swift
├── SwiftyHue Example
├── AppDelegate.swift
├── Base.lproj
│ ├── LaunchScreen.xib
│ └── Main.storyboard
├── BridgeAccessConfigPresentationViewController.swift
├── BridgePushLinkViewController.swift
├── BridgeResourceTableViewController.swift
├── BridgeSelectionTableViewController.swift
├── CreateBridgeAccessController.swift
├── Images.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Contents.json
│ └── PressSmartbridgeV2.imageset
│ │ ├── Contents.json
│ │ └── press_smartbridgeV2.pdf
├── Info.plist
├── SwiftyHue Example-Bridging-Header.h
├── UITableViewController+Extensions.swift
└── ViewController.swift
├── SwiftyHue iOSTests
├── BridgeAuthenticatorConsumer.swift
├── BridgeAuthenticatorTests.swift
├── BridgeFinderConsumer.swift
├── BridgeFinderTests.swift
├── BridgeResultParserTests.swift
├── Info.plist
├── TestBadValidator.swift
├── TestGoodValidator.swift
├── TestScanner1.swift
├── TestScanner2.swift
└── bridge_response.xml
├── SwiftyHue macOSTests
└── Info.plist
├── SwiftyHue.playground
├── Contents.swift
└── contents.xcplayground
├── SwiftyHue.podspec
├── SwiftyHue.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── xcshareddata
│ └── xcschemes
│ ├── SwiftyHue iOS.xcscheme
│ ├── SwiftyHue macOS.xcscheme
│ ├── SwiftyHue tvOS.xcscheme
│ └── SwiftyHue watchOS.xcscheme
├── SwiftyHue.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ └── IDEWorkspaceChecks.plist
└── bin
└── setup
/.gitignore:
--------------------------------------------------------------------------------
1 | #.DS_Store
2 | .DS_Store
3 | docs/
4 |
5 | # Xcode
6 | #
7 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
8 |
9 | ## Build generated
10 | build/
11 | DerivedData
12 |
13 | ## Various settings
14 | *.pbxuser
15 | !default.pbxuser
16 | *.mode1v3
17 | !default.mode1v3
18 | *.mode2v3
19 | !default.mode2v3
20 | *.perspectivev3
21 | !default.perspectivev3
22 | xcuserdata
23 |
24 | ## Other
25 | *.xccheckout
26 | *.moved-aside
27 | *.xcuserstate
28 | *.xcscmblueprint
29 |
30 | ## Obj-C/Swift specific
31 | *.hmap
32 | *.ipa
33 |
34 | ## Playgrounds
35 | timeline.xctimeline
36 | playground.xcworkspace
37 |
38 | # Swift Package Manager
39 | #
40 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
41 | # Packages/
42 | .build/
43 |
44 | # CocoaPods
45 | #
46 | # We recommend against adding the Pods directory to your .gitignore. However
47 | # you should judge for yourself, the pros and cons are mentioned at:
48 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
49 | #
50 | Pods/
51 |
52 | # Carthage
53 | #
54 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
55 |
56 | Carthage/Checkouts
57 | Carthage/Build
58 |
59 | # fastlane
60 | #
61 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
62 | # screenshots whenever they are needed.
63 | # For more information about the recommended setup visit:
64 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md
65 |
66 | fastlane/report.xml
67 | fastlane/screenshots
68 |
--------------------------------------------------------------------------------
/Cartfile:
--------------------------------------------------------------------------------
1 | github "Alamofire/Alamofire" "4.8.0"
2 | github "robbiehanson/CocoaAsyncSocket" "7.6.3"
3 | github "hkellaway/Gloss" "3.1.0"
4 |
--------------------------------------------------------------------------------
/Cartfile.private:
--------------------------------------------------------------------------------
1 | github "luisobo/Nocilla" ~> 0.11.0
2 |
--------------------------------------------------------------------------------
/Cartfile.resolved:
--------------------------------------------------------------------------------
1 | github "Alamofire/Alamofire" "4.8.0"
2 | github "hkellaway/Gloss" "3.1.0"
3 | github "luisobo/Nocilla" "0.11.0"
4 | github "robbiehanson/CocoaAsyncSocket" "7.6.3"
5 |
--------------------------------------------------------------------------------
/Info-macOS.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Marcel Dittmann
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeAccessConfig.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BridgeAccessConfig.swift
3 | // Pods
4 | //
5 | // Created by Marcel Dittmann on 06.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public struct BridgeAccessConfig: JSONDecodable {
13 |
14 | public let bridgeId: String;
15 | public let ipAddress: String;
16 | public let username: String;
17 |
18 | public init(bridgeId: String, ipAddress: String, username: String) {
19 |
20 | self.bridgeId = bridgeId;
21 | self.ipAddress = ipAddress;
22 | self.username = username;
23 |
24 | }
25 |
26 | public init?(json: JSON) {
27 |
28 | guard let bridgeId: String = "id" <~~ json,
29 | let ipAddress: String = "ipaddress" <~~ json,
30 | let username: String = "username" <~~ json
31 |
32 | else { return nil }
33 |
34 | self.bridgeId = bridgeId
35 | self.ipAddress = ipAddress
36 | self.username = username
37 |
38 | }
39 |
40 | public func toJSON() -> JSON? {
41 |
42 | let json = jsonify([
43 | "id" ~~> bridgeId,
44 | "ipaddress" ~~> ipAddress,
45 | "username" ~~> username
46 | ])
47 |
48 | return json
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/AppData.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppData.swift
3 | // Pods
4 | //
5 | // Created by Marcel Dittmann on 21.04.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public struct AppData: Glossy {
13 |
14 | /**
15 | App specific version of the data field. App should take versioning into account when parsing the data string.
16 | */
17 | public let version: Int
18 |
19 | /**
20 | App specific data. Free format string.
21 | */
22 | public let data: String
23 |
24 | public init(version: Int, data: String) {
25 |
26 | self.version = version
27 | self.data = data
28 | }
29 |
30 | public init?(json: JSON) {
31 |
32 | guard let version: Int = "version" <~~ json, let data: String = "data" <~~ json else {
33 | return nil
34 | }
35 |
36 | self.version = version
37 | self.data = data
38 | }
39 |
40 | public func toJSON() -> JSON? {
41 |
42 | return jsonify([
43 | "version" ~~> version,
44 | "data" ~~> data,
45 | ])
46 | }
47 | }
48 |
49 | extension AppData: Hashable {
50 |
51 | public func hash(into hasher: inout Hasher) {
52 | hasher.combine(version)
53 | }
54 | }
55 | public func ==(lhs: AppData, rhs: AppData) -> Bool {
56 | return lhs.version == rhs.version && lhs.data == rhs.data
57 | }
58 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Backup.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Backup.swift
3 | // Pods
4 | //
5 | // Created by Marcel Dittmann on 22.04.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public enum BackupStatus: String {
13 |
14 | case idle, startmigration, fileready_disabled, prepare_restore, restoring
15 | }
16 |
17 | public enum BackupError: Int {
18 |
19 | case none, exportFailed, importFailed
20 | }
21 |
22 | public struct Backup: JSONDecodable {
23 |
24 | public let status: BackupStatus?
25 | public let errorcode: BackupError?
26 |
27 | public init?(json: JSON) {
28 |
29 | status = "status" <~~ json
30 | errorcode = "errorcode" <~~ json
31 |
32 | }
33 |
34 | public func toJSON() -> JSON? {
35 |
36 | let json = jsonify([
37 | "status" ~~> status,
38 | "errorcode" ~~> errorcode
39 | ])
40 |
41 | return json
42 | }
43 | }
44 | extension Backup: Hashable {
45 |
46 | public func hash(into hasher: inout Hasher) {
47 |
48 | hasher.combine(1)
49 | }
50 | }
51 | public func ==(lhs: Backup, rhs: Backup) -> Bool {
52 | return lhs.status == rhs.status && lhs.errorcode == rhs.errorcode
53 | }
54 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/BridgeResource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BridgeResource.swift
3 | // Pods
4 | //
5 | // Created by Marcel Dittmann on 21.04.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public enum BridgeResourceType: String {
13 | case light, group, scene, sensor, rule, config, schedule, whitelistEntry
14 | }
15 |
16 | public protocol BridgeResource: Glossy {
17 |
18 | var identifier: String {get}
19 | var name: String {get}
20 | var resourceType: BridgeResourceType {get};
21 | }
22 |
23 | /**
24 | Can create a dictionary of a specific BridgeResource (BridgeResourceType) from a JSON ([String: AnyObject]).
25 | */
26 | public protocol BridgeResourceDictGenerator {
27 |
28 | associatedtype AssociatedBridgeResourceType: BridgeResource
29 |
30 | static func dictionaryFromResourcesJSON(_ json: JSON) -> [String: AssociatedBridgeResourceType]
31 | }
32 |
33 | public extension BridgeResourceDictGenerator {
34 |
35 | static func dictionaryFromResourcesJSON(_ json: JSON) -> [String: AssociatedBridgeResourceType] {
36 |
37 | var dict = [String: AssociatedBridgeResourceType]();
38 |
39 | for (key, value) in json {
40 |
41 | var resourceJSON = value as! JSON
42 | resourceJSON["id"] = key
43 |
44 | if let resource = AssociatedBridgeResourceType(json: resourceJSON) {
45 | dict[key ] = resource;
46 | }
47 | }
48 |
49 | return dict;
50 | }
51 | }
52 |
53 | //extension BridgeResource {
54 | //
55 | // public init?(json: JSON) {
56 | //
57 | // self.init()
58 | //
59 | // identifier = "id" <~~ json
60 | // name = "name" <~~ json
61 | //
62 | // }
63 | //
64 | // /**
65 | // Object encoded as JSON
66 | // */
67 | // public func toJSON() -> JSON? {
68 | //
69 | // return jsonify([
70 | // "id" ~~> self.identifier,
71 | // "login" ~~> self.name
72 | // ])
73 | // }
74 | //
75 | // public static func dictionaryOf(json: JSON) -> [String: BridgeResource]? {
76 | //
77 | // var dict = [String: BridgeResource]();
78 | //
79 | // for (key, value) in json {
80 | //
81 | // var groupJSON = value as! JSON
82 | // groupJSON["id"] = key
83 | //
84 | // if let group = self.init(json: groupJSON) {
85 | // dict[key as! String] = group;
86 | // }
87 | //
88 | // }
89 | //
90 | // return nil;
91 | // }
92 | //}
93 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Error.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Error.swift
3 | // Pods
4 | //
5 | // Created by Marcel Dittmann on 29.04.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public enum SHErrorType: Int {
13 | case unknownError = 0
14 | case unauthorizedUser = 1
15 | case bodyContainsInvalidJSON = 2
16 | case resourceNotAvailable = 3
17 | case methodNotAvailableForResource = 4
18 | case missingParametersBody = 5
19 | case parameterNotAvailable = 6
20 | case invalidValueParameter = 7
21 | case parameterIsNotModifiable = 8
22 | case tooManyItemsInList = 9
23 | case portalConnectionRequired = 10
24 | case internalError = 901
25 | }
26 |
27 | public class HueError: NSError, JSONDecodable {
28 |
29 | public let address: String
30 | public let errorDescription: String
31 | public let type: SHErrorType
32 |
33 | public required init?(json: JSON) {
34 |
35 | if let _: Any = "success" <~~ json {
36 | return nil
37 | }
38 |
39 | guard let type: Int = "error.type" <~~ json,
40 | let address: String = "error.address" <~~ json,
41 | let errorDescription: String = "error.description" <~~ json
42 | else { print("Can't create Error Object from JSON:\n \(json)"); return nil }
43 |
44 | if let type = SHErrorType(rawValue: type) {
45 | self.type = type
46 | } else {
47 | self.type = .unknownError
48 | }
49 |
50 | self.address = address
51 | self.errorDescription = errorDescription
52 |
53 | super.init(domain: address, code: type, userInfo: ["description": errorDescription])
54 | }
55 |
56 | public init(address: String, errorDescription: String, type: SHErrorType) {
57 |
58 | self.type = type
59 | self.address = address
60 | self.errorDescription = errorDescription
61 |
62 | super.init(domain: address, code: type.rawValue, userInfo: ["description": errorDescription])
63 | }
64 |
65 | public init?(address: String, errorDescription: String, type: Int) {
66 |
67 | guard let errorType = SHErrorType(rawValue: type) else {return nil};
68 |
69 | self.type = errorType;
70 | self.address = address
71 | self.errorDescription = errorDescription
72 |
73 | super.init(domain: address, code: type, userInfo: ["description": errorDescription])
74 | }
75 |
76 | required public init?(coder aDecoder: NSCoder) {
77 | fatalError("init(coder:) has not been implemented")
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Group.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Group.swift
3 | // Pods
4 | //
5 | // Created by Marcel Dittmann on 21.04.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public enum GroupType: String {
13 |
14 | case LightGroup, Room, Luminaire, LightSource, Entertainment, Zone
15 | }
16 |
17 | public enum RoomClass: String {
18 |
19 | case LivingRoom = "Living room", Kitchen, Dining, Bedroom, KidsBedroom = "Kids bedroom", Bathroom, Nursery, Recreation, Office, Gym, Hallway, Toilet, FrontDoor = "Front door", Garage, Terrace, Garden, Driveway, Carport, Other, Home, Downstairs, Upstairs, TopFloor = "Top floor", Attic, GuestRoom = "Guest room", Staircase, Lounge, ManCave = "Man cave", Computer, Studio, Music, TV, Reading, Closet, Storage, LaundryRoom = "Laundry room", Balcony, Porch, Barbecue, Pool
20 | }
21 |
22 | public class Group: BridgeResourceDictGenerator, BridgeResource {
23 |
24 | public typealias AssociatedBridgeResourceType = Group;
25 |
26 | public var resourceType: BridgeResourceType {
27 | return .group
28 | };
29 |
30 | public var identifier: String
31 | public var name: String
32 |
33 | /**
34 | The light state of one of the lamps in the group.
35 | */
36 | public let action: LightState;
37 |
38 | /**
39 | The IDs of the lights that are in the group.
40 | */
41 | public let lightIdentifiers: [String]?;
42 |
43 | /**
44 | As of 1.4. If not provided upon creation "LightGroup" is used. Can be "LightGroup", "Room" or either "Luminaire" or "LightSource" if a Multisource Luminaire is present in the system.
45 | */
46 | public let type: GroupType
47 |
48 | /**
49 | As of 1.4. Uniquely identifies the hardware model of the luminaire. Only present for automatically created Luminaires.
50 | */
51 | public let modelId: String?
52 |
53 | /**
54 | As of 1.9. Unique Id in AA:BB:CC:DD format for Luminaire groups or AA:BB:CC:DD-XX format for Lightsource groups, where XX is the lightsource position.
55 | */
56 | public let uniqueId: String?
57 |
58 | /**
59 | As of 1.11. Category of Room types. Default is: Other.
60 | */
61 | public let roomClass: RoomClass
62 |
63 | public required init?(json: JSON) {
64 |
65 | guard let identifier: String = "id" <~~ json,
66 | let name: String = "name" <~~ json,
67 | let action: LightState = "action" <~~ json,
68 | let type: GroupType = "type" <~~ json,
69 | let roomClass: RoomClass = RoomClass(rawValue: ("class" <~~ json) ?? "Other")
70 |
71 | else { print("Can't create Group from JSON:\n \(json)"); return nil }
72 |
73 | self.identifier = identifier
74 | self.name = name
75 | self.action = action
76 | self.type = type
77 | self.roomClass = roomClass
78 |
79 | uniqueId = "uniqueid" <~~ json
80 | modelId = "modelid" <~~ json
81 | lightIdentifiers = "lights" <~~ json
82 | }
83 |
84 | public func toJSON() -> JSON? {
85 |
86 | let json = jsonify([
87 | "id" ~~> identifier,
88 | "name" ~~> name,
89 | "action" ~~> action,
90 | "lights" ~~> lightIdentifiers,
91 | "type" ~~> type,
92 | "modelid" ~~> modelId,
93 | "uniqueid" ~~> uniqueId,
94 | "class" ~~> roomClass.rawValue
95 | ])
96 |
97 | return json
98 | }
99 |
100 | }
101 |
102 | extension Group: Hashable {
103 |
104 | public func hash(into hasher: inout Hasher) {
105 |
106 | hasher.combine(Int(self.identifier)!)
107 | }
108 | }
109 |
110 | public func ==(lhs: Group, rhs: Group) -> Bool {
111 | return lhs.identifier == rhs.identifier
112 | }
113 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Light.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Light.swift
3 | // Pods
4 | //
5 | // Created by Marcel Dittmann on 21.04.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class Light: BridgeResource, BridgeResourceDictGenerator {
13 |
14 | public typealias AssociatedBridgeResourceType = Light
15 |
16 | public var resourceType: BridgeResourceType {
17 | return .light
18 | };
19 |
20 | /**
21 | Identifier of the light.
22 | */
23 | public let identifier: String
24 |
25 | /**
26 | A unique, editable name given to the light.
27 | */
28 | public let name: String
29 |
30 | /**
31 | Details the state of the light.
32 | */
33 | public let state: LightState
34 |
35 | /**
36 | A fixed name describing the type of light e.g. “Extended color light”.
37 | */
38 | public let type: String
39 |
40 | /**
41 | The hardware model of the light.
42 | */
43 | public let modelId: String
44 |
45 | /**
46 | As of 1.4. Unique id of the device. The MAC address of the device with a unique endpoint id in the form: AA:BB:CC:DD:EE:FF:00:11-XX
47 | */
48 | public let uniqueId: String
49 |
50 | /**
51 | As of 1.7. The manufacturer name.
52 | */
53 | public let manufacturerName: String
54 |
55 | /**
56 | As of 1.9. Unique ID of the luminaire the light is a part of in the format: AA:BB:CC:DD-XX-YY. AA:BB:, ... represents the hex of the luminaireid, XX the lightsource position (incremental but may contain gaps) and YY the lightpoint position (index of light in luminaire group). A gap in the lightpoint position indicates an incomplete luminaire (light search required to discover missing light points in this case).
57 | */
58 | public let luminaireUniqueId: String?
59 |
60 | /**
61 | An identifier for the software version running on the light.
62 | */
63 | public let swVersion: String
64 |
65 | /**
66 | This parameter is reserved for future functionality. As from 1.11 point symbols are no longer returned.
67 | */
68 | public let pointsymbol: String?
69 |
70 | public required init?(json: JSON) {
71 |
72 | guard let identifier: String = "id" <~~ json,
73 | let name: String = "name" <~~ json,
74 | let state: LightState = "state" <~~ json,
75 | let type: String = "type" <~~ json,
76 | let modelid: String = "modelid" <~~ json,
77 | let uniqueid: String = "uniqueid" <~~ json,
78 | let manufacturername: String = "manufacturername" <~~ json,
79 | let swversion: String = "swversion" <~~ json
80 |
81 | else { print("Can't create Light from JSON:\n \(json)"); return nil }
82 |
83 | self.identifier = identifier
84 | self.name = name
85 | self.state = state
86 | self.type = type
87 | self.modelId = modelid
88 | self.uniqueId = uniqueid
89 | self.manufacturerName = manufacturername
90 | self.swVersion = swversion
91 |
92 | luminaireUniqueId = "luminaireuniqueid" <~~ json
93 | pointsymbol = "pointsymbol" <~~ json
94 |
95 | }
96 |
97 | public func toJSON() -> JSON? {
98 |
99 | let json = jsonify([
100 | "id" ~~> identifier,
101 | "name" ~~> name,
102 | "state" ~~> state,
103 | "type" ~~> type,
104 | "modelid" ~~> modelId,
105 | "uniqueid" ~~> uniqueId,
106 | "manufacturername" ~~> manufacturerName,
107 | "luminaireuniqueid" ~~> luminaireUniqueId,
108 | "swversion" ~~> swVersion,
109 | "pointsymbol" ~~> pointsymbol
110 | ])
111 |
112 | return json
113 | }
114 | }
115 |
116 | extension Light: Hashable {
117 |
118 | public func hash(into hasher: inout Hasher) {
119 |
120 | hasher.combine(Int(self.identifier)!)
121 | }
122 | }
123 |
124 | public func ==(lhs: Light, rhs: Light) -> Bool {
125 | return lhs.identifier == rhs.identifier
126 | }
127 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/LightState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LightState.swift
3 | // Pods
4 | //
5 | // Created by Marcel Dittmann on 21.04.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public struct LightState: JSONDecodable, JSONEncodable {
13 |
14 | /**
15 | The on off status to set the light to.
16 | true means on, false means off.
17 | */
18 | public var on: Bool?;
19 |
20 | /**
21 | The brightness to set the light to.
22 | Range: 0 (lowest brightness, but not off) to 254 (highest brightness).
23 | */
24 | public var brightness: Int?;
25 |
26 | /**
27 | The hue to set the light to, representing a color.
28 | Range: 0 - 65535 (which represents 0-360 degrees)
29 | Explanation: http://en.wikipedia.org/wiki/Hue
30 | */
31 | public var hue: Int?;
32 |
33 | /**
34 | The saturation to set the light to.
35 | Range: 0 (least saturated, white) - 254 (most saturated, vivid).
36 | */
37 | public var saturation: Int?;
38 |
39 | public var xy: [Double]?;
40 |
41 | /**
42 | The colortemperature to set the light to in Mirek
43 | Range of 2012 hue bulb: 153 (coldest white) - 500 (warmest white)
44 | Range of 2014 tone light module: 153 (coldest white) - 454 (warmest white)
45 | Explanation: http://en.wikipedia.org/wiki/Mired
46 | */
47 | public var ct: Int?;
48 | public var alert: String?;
49 | public var effect: String?;
50 | public var colormode: String?;
51 | public var reachable: Bool?;
52 | public var transitiontime: Int?;
53 |
54 | public init() {
55 |
56 | }
57 |
58 | public init?(json: JSON) {
59 |
60 | self.on = "on" <~~ json
61 | self.brightness = "bri" <~~ json
62 | self.hue = "hue" <~~ json
63 | self.saturation = "sat" <~~ json
64 | self.xy = "xy" <~~ json
65 | self.ct = "ct" <~~ json
66 | self.alert = "alert" <~~ json
67 | self.effect = "effect" <~~ json
68 | self.colormode = "colormode" <~~ json
69 | self.reachable = "reachable" <~~ json
70 | self.transitiontime = "transitiontime" <~~ json
71 | }
72 |
73 | public func toJSON() -> JSON? {
74 |
75 | return jsonify([
76 | "on" ~~> on,
77 | "bri" ~~> brightness,
78 | "hue" ~~> hue,
79 | "sat" ~~> saturation,
80 | "xy" ~~> xy,
81 | "ct" ~~> ct,
82 | "alert" ~~> alert,
83 | "effect" ~~> effect,
84 | "colormode" ~~> colormode,
85 | "reachable" ~~> reachable,
86 | "transitiontime" ~~> transitiontime
87 |
88 | ])
89 | }
90 | }
91 |
92 | extension LightState: Hashable {
93 |
94 | public func hash(into hasher: inout Hasher) {
95 | hasher.combine(self.brightness ?? 0)
96 | hasher.combine(self.hue ?? 0)
97 | hasher.combine(self.saturation ?? 0)
98 | }
99 | }
100 |
101 | public func ==(lhs: LightState, rhs: LightState) -> Bool {
102 | return lhs.on == rhs.on &&
103 | lhs.brightness == rhs.brightness &&
104 | lhs.hue == rhs.hue &&
105 | lhs.saturation == rhs.saturation &&
106 | (lhs.xy ?? [-1, -1]) == (rhs.xy ?? [-1, -1]) &&
107 | lhs.ct == rhs.ct &&
108 | lhs.alert == rhs.alert &&
109 | lhs.effect == rhs.effect &&
110 | lhs.colormode == rhs.colormode &&
111 | lhs.reachable == rhs.reachable &&
112 | lhs.transitiontime == rhs.transitiontime
113 | }
114 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/PortalState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PortalState.swift
3 | // Pods
4 | //
5 | // Created by Marcel Dittmann on 22.04.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public enum PortalStateCommunication: String {
13 |
14 | case connected, connecting, disconnected, unknown
15 | }
16 |
17 | public struct PortalState: JSONDecodable {
18 |
19 | /**
20 | The bridge is signed on the portal
21 | */
22 | public let signedon: Bool?
23 |
24 | /**
25 | The bridge is able to send messages to the portal
26 | */
27 | public let incoming: Bool?
28 |
29 | /**
30 | The bridge is able to recieve messages from the portal
31 | */
32 | public let outgoing: Bool?
33 |
34 | /**
35 | The bridge is communicating with SmartPortal
36 | */
37 | public let communication: PortalStateCommunication?
38 |
39 | public init?(json: JSON) {
40 |
41 | signedon = "signedon" <~~ json
42 | incoming = "incoming" <~~ json
43 | outgoing = "outgoing" <~~ json
44 | communication = "communication" <~~ json
45 |
46 | }
47 |
48 | public func toJSON() -> JSON? {
49 |
50 | let json = jsonify([
51 | "signedon" ~~> signedon,
52 | "incoming" ~~> incoming,
53 | "outgoing" ~~> outgoing,
54 | "communication" ~~> communication
55 | ])
56 |
57 | return json
58 | }
59 | }
60 |
61 | extension PortalState: Hashable {
62 |
63 | public func hash(into hasher: inout Hasher) {
64 |
65 | hasher.combine(1)
66 | }
67 | }
68 |
69 | public func ==(lhs: PortalState, rhs: PortalState) -> Bool {
70 | return lhs.signedon == rhs.signedon &&
71 | lhs.incoming == rhs.incoming &&
72 | lhs.outgoing == rhs.outgoing &&
73 | lhs.communication == rhs.communication
74 | }
75 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Rule/Rule.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Rule.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class Rule: BridgeResource, BridgeResourceDictGenerator {
13 |
14 | public typealias AssociatedBridgeResourceType = Rule
15 |
16 | public var resourceType: BridgeResourceType {
17 | return .rule
18 | };
19 |
20 | public let identifier: String
21 | public let name: String
22 | public let lasttriggered: Date?
23 | public let created: Date
24 | public let timestriggered: Int
25 | public let owner: String
26 | public let status: String
27 | public let conditions: [RuleCondition]
28 | public let actions: [RuleAction]
29 |
30 | public required init?(json: JSON) {
31 |
32 | let dateFormatter = DateFormatter.hueApiDateFormatter
33 |
34 | guard let identifier: String = "id" <~~ json else {
35 | print("Can't create Rule, missing required attribute \"id\" in JSON:\n \(json)"); return nil
36 | }
37 |
38 | guard let name: String = "name" <~~ json else {
39 | print("Can't create Rule, missing required attribute \"name\" in JSON:\n \(json)"); return nil
40 | }
41 |
42 | guard let created: Date = Decoder.decode(dateForKey:"created", dateFormatter:dateFormatter)(json) else {
43 | print("Can't create Rule, missing required attribute \"created\" in JSON:\n \(json)"); return nil
44 | }
45 |
46 | guard let timestriggered: Int = "timestriggered" <~~ json else {
47 | print("Can't create Rule, missing required attribute \"timestriggered\" in JSON:\n \(json)"); return nil
48 | }
49 |
50 | guard let owner: String = "owner" <~~ json else {
51 | print("Can't create Rule, missing required attribute \"owner\" in JSON:\n \(json)"); return nil
52 | }
53 |
54 | guard let status: String = "status" <~~ json else {
55 | print("Can't create Rule, missing required attribute \"status\" in JSON:\n \(json)"); return nil
56 | }
57 |
58 | guard let conditionJSONs: [JSON] = "conditions" <~~ json else {
59 | print("Can't create Rule, missing required attribute \"conditions\" in JSON:\n \(json)"); return nil
60 | }
61 |
62 | guard let actionJSONs: [JSON] = "actions" <~~ json else {
63 | print("Can't create Rule, missing required attribute \"actions\" in JSON:\n \(json)"); return nil
64 | }
65 |
66 |
67 | self.identifier = identifier
68 | self.name = name
69 | self.created = created as Date
70 | self.lasttriggered = Decoder.decode(dateForKey:"lasttriggered", dateFormatter:dateFormatter)(json)
71 | self.timestriggered = timestriggered
72 | self.owner = owner
73 | self.status = status
74 | self.conditions = [RuleCondition].from(jsonArray: conditionJSONs)!
75 | self.actions = [RuleAction].from(jsonArray: actionJSONs)!
76 | }
77 |
78 | public func toJSON() -> JSON? {
79 |
80 | let dateFormatter = DateFormatter.hueApiDateFormatter
81 |
82 | let json = jsonify([
83 | "id" ~~> self.identifier,
84 | "name" ~~> self.name,
85 | Encoder.encode(dateForKey: "created", dateFormatter: dateFormatter)(self.created),
86 | Encoder.encode(dateForKey: "lasttriggered", dateFormatter: dateFormatter)(self.lasttriggered),
87 | "timestriggered" ~~> self.timestriggered,
88 | "owner" ~~> self.owner,
89 | "status" ~~> self.status,
90 | "conditions" ~~> self.conditions,
91 | "actions" ~~> self.actions
92 | ])
93 |
94 | return json
95 | }
96 | }
97 |
98 | extension Rule: Hashable {
99 |
100 | public func hash(into hasher: inout Hasher) {
101 |
102 | hasher.combine(Int(self.identifier)!)
103 | }
104 | }
105 |
106 | public func ==(lhs: Rule, rhs: Rule) -> Bool {
107 | return lhs.identifier == rhs.identifier &&
108 | lhs.name == rhs.name &&
109 | lhs.created == rhs.created &&
110 | lhs.lasttriggered == rhs.lasttriggered &&
111 | lhs.timestriggered == rhs.timestriggered &&
112 | lhs.owner == rhs.owner &&
113 | lhs.status == rhs.status &&
114 | lhs.conditions == rhs.conditions &&
115 | lhs.actions == rhs.actions
116 | }
117 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Rule/RuleAction.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RuleAction.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class RuleAction: Glossy {
13 |
14 | public let address: String
15 | public let method: String
16 | public let body: [String: Any]
17 |
18 | public required init?(json: JSON) {
19 |
20 | guard let address: String = "address" <~~ json else {
21 | print("Can't create RuleAction, missing required attribute \"address\" in JSON:\n \(json)"); return nil
22 | }
23 |
24 | guard let method: String = "method" <~~ json else {
25 | print("Can't create RuleAction, missing required attribute \"method\" in JSON:\n \(json)"); return nil
26 | }
27 |
28 | guard let body: JSON = "body" <~~ json else {
29 | print("Can't create RuleAction, missing required attribute \"body\" in JSON:\n \(json)"); return nil
30 | }
31 |
32 | self.address = address
33 | self.method = method
34 | self.body = body
35 | }
36 |
37 | public func toJSON() -> JSON? {
38 |
39 | let json = jsonify([
40 | "address" ~~> address,
41 | "method" ~~> method,
42 | "body" ~~> body
43 | ])
44 |
45 | return json
46 | }
47 | }
48 |
49 | extension RuleAction: Hashable {
50 |
51 | public func hash(into hasher: inout Hasher) {
52 |
53 | hasher.combine(1)
54 | }
55 | }
56 |
57 | public func ==(lhs: RuleAction, rhs: RuleAction) -> Bool {
58 | return lhs.address == rhs.address &&
59 | lhs.method == rhs.method// &&
60 | // lhs.body == rhs.body
61 | }
62 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Rule/RuleCondition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RuleCondition.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public enum RuleConditionOperator: String {
13 | case EQ = "eq", GT = "gt", LT = "lt", DX = "dx", DDX = "ddx"
14 |
15 | }
16 |
17 | public class RuleCondition: Glossy {
18 |
19 | public let address: String
20 | public let conditionOperator: RuleConditionOperator?
21 | public let value: String?
22 |
23 | public required init?(json: JSON) {
24 |
25 | guard let address: String = "address" <~~ json else {
26 | print("Can't create RuleCondition, missing required attribute \"address\" in JSON:\n \(json)"); return nil
27 | }
28 |
29 | // guard let conditionOperator: RuleConditionOperator = "operator" <~~ json else {
30 | // Log.error("Can't create RuleCondition, missing required attribute \"operator\" in JSON:\n \(json)"); return nil
31 | // }
32 |
33 | self.address = address
34 |
35 | self.conditionOperator = "operator" <~~ json
36 | self.value = "value" <~~ json
37 | }
38 |
39 | public func toJSON() -> JSON? {
40 |
41 | let json = jsonify([
42 | "address" ~~> address,
43 | "operator" ~~> conditionOperator,
44 | "value" ~~> value
45 | ])
46 |
47 | return json
48 | }
49 | }
50 |
51 | extension RuleCondition: Hashable {
52 |
53 | public func hash(into hasher: inout Hasher) {
54 |
55 | hasher.combine(1)
56 | }
57 | }
58 |
59 | public func ==(lhs: RuleCondition, rhs: RuleCondition) -> Bool {
60 | return lhs.address == rhs.address &&
61 | lhs.conditionOperator == rhs.conditionOperator &&
62 | lhs.value == rhs.value
63 | }
64 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Scene.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Scene.swift
3 | // Pods
4 | //
5 | // Created by Marcel Dittmann on 21.04.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | //public class Scene: PartialScene {
13 | //
14 | // public let lightstates: [LightState]?;
15 | //
16 | // public required init?(json: JSON) {
17 | //
18 | // var lightStates = json["lightstates"]
19 | //
20 | // if lightStates != nil {
21 | //
22 | // var lightstateJSONS = TestRequester.convert((lightStates as! NSDictionary).mutableCopy() as! NSMutableDictionary)
23 | // self.lightstates = Array.from(jsonArray: lightstateJSONS);
24 | //
25 | // } else {
26 | // self.lightstates = nil;
27 | // }
28 | //
29 | // super.init(json: json)
30 | // }
31 | //
32 | //}
33 |
34 | public class PartialScene: BridgeResource, BridgeResourceDictGenerator {
35 |
36 | public typealias AssociatedBridgeResourceType = PartialScene
37 |
38 | public var resourceType: BridgeResourceType {
39 | return .scene
40 | };
41 |
42 | /**
43 | The identifier of this scene.
44 | */
45 | public let identifier: String
46 |
47 | /**
48 | The name of this scene.
49 | */
50 | public let name: String
51 |
52 | /**
53 | The identifiers of the lights controlled by this scene.
54 | */
55 | public let lightIdentifiers: [String]?
56 |
57 | /**
58 | Whitelist user that created or modified the content of the scene. Note that changing name does not change the owner..
59 | */
60 | public let owner: String
61 |
62 | /**
63 | Indicates whether the scene can be automatically deleted by the bridge. Only available by POSTSet to 'false' when omitted. Legacy scenes created by PUT are defaulted to true. When set to 'false' the bridge keeps the scene until deleted by an application.
64 | */
65 | public let recycle: Bool
66 |
67 | /**
68 | Indicates that the scene is locked by a rule or a schedule and cannot be deleted until all resources requiring or that reference the scene are deleted.
69 | */
70 | public let locked: Bool
71 |
72 | /**
73 | App specific data linked to the scene. Each individual application should take responsibility for the data written in this field.
74 | */
75 | public let appData: AppData?
76 |
77 | /**
78 | UTC time the scene has been created or has been updated by a PUT. Will be null when unknown (legacy scenes).
79 | */
80 | public let lastUpdated: Date?
81 |
82 | /**
83 | Version of scene document:
84 | 1 - Scene created via PUT, lightstates will be empty.
85 | 2 - Scene created via POST lightstates available.
86 | */
87 | public let version: Int
88 |
89 | public required init?(json: JSON) {
90 |
91 | guard let identifier: String = "id" <~~ json,
92 | let name: String = "name" <~~ json,
93 | let lightIdentifiers: [String] = "lights" <~~ json,
94 | let owner: String = "owner" <~~ json,
95 | let recycle: Bool = "recycle" <~~ json,
96 | let locked: Bool = "locked" <~~ json,
97 | let version: Int = "version" <~~ json
98 |
99 | else { print("Can't create Partial Scene from JSON:\n \(json)"); return nil }
100 |
101 | self.identifier = identifier
102 | self.name = name
103 | self.lightIdentifiers = lightIdentifiers
104 | self.owner = owner
105 | self.recycle = recycle
106 | self.locked = locked
107 | self.version = version
108 |
109 | let dateFormatter = DateFormatter.hueApiDateFormatter
110 |
111 | self.appData = "appdata" <~~ json
112 | lastUpdated = Decoder.decode(dateForKey:"lastupdated", dateFormatter:dateFormatter)(json)
113 | }
114 |
115 | public func toJSON() -> JSON? {
116 |
117 | let dateFormatter = DateFormatter.hueApiDateFormatter
118 |
119 | let json = jsonify([
120 | "id" ~~> identifier,
121 | "name" ~~> name,
122 | "lights" ~~> lightIdentifiers,
123 | "owner" ~~> owner,
124 | "recycle" ~~> recycle,
125 | "locked" ~~> locked,
126 | "appdata" ~~> appData,
127 | Encoder.encode(dateForKey: "lastupdated", dateFormatter: dateFormatter)(lastUpdated),
128 | "version" ~~> version
129 | ])
130 |
131 | return json
132 | }
133 |
134 | }
135 |
136 | extension PartialScene: Hashable {
137 |
138 | public func hash(into hasher: inout Hasher) {
139 |
140 | hasher.combine(Int(self.identifier)!)
141 | }
142 | }
143 |
144 | public func ==(lhs: PartialScene, rhs: PartialScene) -> Bool {
145 |
146 | return lhs.identifier == rhs.identifier &&
147 | lhs.name == rhs.name &&
148 | (lhs.lightIdentifiers ?? []) == (rhs.lightIdentifiers ?? []) &&
149 | lhs.owner == rhs.owner &&
150 | lhs.recycle == rhs.recycle &&
151 | lhs.locked == rhs.locked &&
152 | lhs.appData == rhs.appData &&
153 | lhs.lastUpdated == rhs.lastUpdated &&
154 | lhs.version == rhs.version
155 | }
156 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Schedule/Schedule.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Schedule.swift
3 | //
4 | //
5 | // Created by Jerome Schmitz on 05.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class Schedule: BridgeResource, BridgeResourceDictGenerator {
13 |
14 | public typealias AssociatedBridgeResourceType = Schedule
15 |
16 | public var resourceType: BridgeResourceType {
17 | return .schedule
18 | };
19 |
20 | public let identifier: String
21 | public let name: String
22 | public let scheduleDescription: String
23 | public let command: ScheduleCommand
24 | public let localtime: String?
25 | public let status: String
26 | public let autodelete: Bool?
27 | public let recycle: Bool?
28 |
29 | public required init?(json: JSON) {
30 |
31 | guard let identifier: String = "id" <~~ json else {
32 | print("Can't create Schedule, missing required attribute \"id\" in JSON:\n \(json)"); return nil
33 | }
34 |
35 | guard let name: String = "name" <~~ json else {
36 | print("Can't create Schedule, missing required attribute \"name\" in JSON:\n \(json)"); return nil
37 | }
38 |
39 | guard let scheduleDescription: String = "description" <~~ json else {
40 | print("Can't create Schedule, missing required attribute \"description\" in JSON:\n \(json)"); return nil
41 | }
42 |
43 | guard let command: ScheduleCommand = "command" <~~ json else {
44 | print("Can't create Schedule, missing required attribute \"command\" in JSON:\n \(json)"); return nil
45 | }
46 |
47 | guard let status: String = "status" <~~ json else {
48 | print("Can't create Schedule, missing required attribute \"status\" in JSON:\n \(json)"); return nil
49 | }
50 |
51 | self.identifier = identifier
52 | self.name = name
53 | self.scheduleDescription = scheduleDescription
54 | self.command = command
55 | self.status = status
56 | self.recycle = "recycle" <~~ json
57 | self.autodelete = "autodelete" <~~ json
58 | self.localtime = "localtime" <~~ json
59 | }
60 |
61 | public func toJSON() -> JSON? {
62 |
63 | let json = jsonify([
64 | "id" ~~> identifier,
65 | "name" ~~> name,
66 | "description" ~~> scheduleDescription,
67 | "command" ~~> command,
68 | "localtime" ~~> localtime,
69 | "status" ~~> status,
70 | "autodelete" ~~> autodelete,
71 | "recycle" ~~> recycle
72 | ])
73 |
74 | return json
75 | }
76 | }
77 |
78 | extension Schedule: Hashable {
79 |
80 | public func hash(into hasher: inout Hasher) {
81 |
82 | hasher.combine(1)
83 | }
84 | }
85 |
86 | public func ==(lhs: Schedule, rhs: Schedule) -> Bool {
87 | return lhs.identifier == rhs.identifier &&
88 | lhs.name == rhs.name &&
89 | lhs.scheduleDescription == rhs.scheduleDescription &&
90 | lhs.command == rhs.command &&
91 | lhs.status == rhs.status &&
92 | lhs.recycle == rhs.recycle &&
93 | lhs.autodelete == rhs.autodelete &&
94 | lhs.localtime == rhs.localtime
95 | }
96 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Schedule/ScheduleCommand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScheduleCommand.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 05.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class ScheduleCommand: JSONDecodable {
13 |
14 | public let address: String
15 | public let method: String
16 | public let body: [String: Any]
17 |
18 | public required init?(json: JSON) {
19 |
20 | guard let address: String = "address" <~~ json else {
21 | print("Can't create ScheduleCommand, missing required attribute \"address\" in JSON:\n \(json)"); return nil
22 | }
23 |
24 | guard let method: String = "method" <~~ json else {
25 | print("Can't create ScheduleCommand, missing required attribute \"method\" in JSON:\n \(json)"); return nil
26 | }
27 |
28 | guard let body: JSON = "body" <~~ json else {
29 | print("Can't create ScheduleCommand, missing required attribute \"body\" in JSON:\n \(json)"); return nil
30 | }
31 |
32 | self.address = address
33 | self.method = method
34 | self.body = body
35 | }
36 |
37 | public func toJSON() -> JSON? {
38 |
39 | let json = jsonify([
40 | "address" ~~> address,
41 | "method" ~~> method,
42 | "body" ~~> body
43 | ])
44 |
45 | return json
46 | }
47 | }
48 |
49 | extension ScheduleCommand: Hashable {
50 |
51 | public func hash(into hasher: inout Hasher) {
52 |
53 | hasher.combine(1)
54 | }
55 | }
56 |
57 | public func ==(lhs: ScheduleCommand, rhs: ScheduleCommand) -> Bool {
58 | return lhs.address == rhs.address &&
59 | lhs.method == rhs.method //&&
60 | // !zip(lhs.body, rhs.body).contains {$0 != $1}
61 | }
62 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/DaylightSensor/DaylightSensor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DaylightSensor.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class DaylightSensor: PartialSensor {
13 |
14 | let config: DaylightSensorConfig
15 | let state: DaylightSensorState
16 |
17 | required public init?(sensor: Sensor) {
18 |
19 | guard let sensorConfig = sensor.config else {
20 | return nil
21 | }
22 |
23 | guard let sensorState = sensor.state else {
24 | return nil
25 | }
26 |
27 | guard let config: DaylightSensorConfig = DaylightSensorConfig(sensorConfig: sensorConfig) else {
28 | return nil
29 | }
30 |
31 | guard let state: DaylightSensorState = DaylightSensorState(state: sensorState) else {
32 | return nil
33 | }
34 |
35 | self.config = config
36 | self.state = state
37 |
38 | super.init(identifier: sensor.identifier, uniqueId: sensor.uniqueId, name: sensor.name, type: sensor.type, modelId: sensor.modelId, manufacturerName: sensor.manufacturerName, swVersion: sensor.swVersion, recycle: sensor.recycle)
39 | }
40 |
41 | public required init?(json: JSON) {
42 |
43 | guard let config: DaylightSensorConfig = "config" <~~ json else {
44 | return nil
45 | }
46 |
47 | guard let state: DaylightSensorState = "state" <~~ json else {
48 | return nil
49 | }
50 |
51 | self.config = config
52 | self.state = state
53 |
54 | super.init(json: json)
55 | }
56 | }
57 |
58 | public func ==(lhs: DaylightSensor, rhs: DaylightSensor) -> Bool {
59 | return lhs.identifier == rhs.identifier &&
60 | lhs.name == rhs.name &&
61 | lhs.state == rhs.state &&
62 | lhs.config == rhs.config &&
63 | lhs.type == rhs.type &&
64 | lhs.modelId == rhs.modelId &&
65 | lhs.manufacturerName == rhs.manufacturerName &&
66 | lhs.swVersion == rhs.swVersion
67 | }
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/DaylightSensor/DaylightSensorConfig.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DaylightSensorConfig.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class DaylightSensorConfig: PartialSensorConfig {
13 |
14 | public let long: String?
15 | public let lat: String?
16 | public let sunriseOffset: Int?
17 | public let sunsetOffset: Int?
18 |
19 | init?(sensorConfig: SensorConfig) {
20 |
21 | // guard let long: String = sensorConfig.long else {
22 | // Log.error("Can't create DaylightSensorConfig, missing required attribute \"long\""); return nil
23 | // }
24 | //
25 | // guard let lat: String = sensorConfig.lat else {
26 | // Log.error("Can't create DaylightSensorConfig, missing required attribute \"lat\""); return nil
27 | // }
28 |
29 | self.long = sensorConfig.long
30 | self.lat = sensorConfig.lat
31 | self.sunriseOffset = sensorConfig.sunriseOffset
32 | self.sunsetOffset = sensorConfig.sunsetOffset
33 |
34 | super.init(on: sensorConfig.on, reachable: sensorConfig.reachable, battery: sensorConfig.battery, url: sensorConfig.url)
35 | }
36 |
37 | required public init?(json: JSON) {
38 |
39 | // guard let long: String = "long" <~~ json else {
40 | // Log.error("Can't create DaylightSensorConfig, missing required attribute \"long\" in JSON:\n \(json)"); return nil
41 | // }
42 | //
43 | // guard let lat: String = "lat" <~~ json else {
44 | // Log.error("Can't create DaylightSensorConfig, missing required attribute \"lat\" in JSON:\n \(json)"); return nil
45 | // }
46 |
47 | self.long = "long" <~~ json
48 | self.lat = "lat" <~~ json
49 | self.sunriseOffset = "sunriseoffset" <~~ json
50 | self.sunsetOffset = "sunsetoffset" <~~ json
51 |
52 | super.init(json: json)
53 | }
54 |
55 | public override func toJSON() -> JSON? {
56 |
57 | if var superJson = super.toJSON() {
58 | let json = jsonify([
59 | "long" ~~> long,
60 | "lat" ~~> lat,
61 | "sunriseoffset" ~~> sunriseOffset,
62 | "sunsetoffset" ~~> sunsetOffset
63 | ])
64 | superJson.unionInPlace(json!)
65 | return superJson
66 | }
67 |
68 | return nil
69 | }
70 | }
71 |
72 | public func ==(lhs: DaylightSensorConfig, rhs: DaylightSensorConfig) -> Bool {
73 | return lhs.on == rhs.on &&
74 | lhs.reachable == rhs.reachable &&
75 | lhs.battery == rhs.battery &&
76 | lhs.url == rhs.url &&
77 | lhs.long == rhs.long &&
78 | lhs.lat == rhs.lat &&
79 | lhs.sunriseOffset == rhs.sunriseOffset &&
80 | lhs.sunsetOffset == rhs.sunsetOffset
81 | }
82 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/DaylightSensor/DaylightSensorState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DaylightSensorState.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class DaylightSensorState: PartialSensorState {
13 |
14 | public let daylight: Bool?
15 |
16 | init?(state: SensorState) {
17 |
18 | self.daylight = state.daylight
19 |
20 | super.init(lastUpdated: state.lastUpdated)
21 | }
22 |
23 | required public init?(json: JSON) {
24 |
25 | guard let daylight: Bool = "daylight" <~~ json else {
26 | print("Can't create DaylightSensorState, missing required attribute \"daylight\" in JSON:\n \(json)"); return nil
27 | }
28 |
29 | self.daylight = daylight
30 |
31 | super.init(json: json)
32 | }
33 |
34 | public override func toJSON() -> JSON? {
35 |
36 | if var superJson = super.toJSON() {
37 | let json = jsonify([
38 | "daylight" ~~> self.daylight
39 | ])
40 | superJson.unionInPlace(json!)
41 | return superJson
42 | }
43 |
44 | return nil
45 | }
46 | }
47 |
48 | public func ==(lhs: DaylightSensorState, rhs: DaylightSensorState) -> Bool {
49 | return lhs.lastUpdated == rhs.lastUpdated &&
50 | lhs.daylight == rhs.daylight
51 | }
52 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/GenericFlagSensor/GenericFlagSensor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GenericFlagSensor.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class GenericFlagSensor: PartialSensor {
13 |
14 | let config: GenericFlagSensorConfig
15 | let state: GenericFlagSensorState
16 |
17 | required public init?(sensor: Sensor) {
18 |
19 | guard let sensorConfig = sensor.config else {
20 | return nil
21 | }
22 |
23 | guard let sensorState = sensor.state else {
24 | return nil
25 | }
26 |
27 | guard let config: GenericFlagSensorConfig = GenericFlagSensorConfig(sensorConfig: sensorConfig) else {
28 | return nil
29 | }
30 |
31 | guard let state: GenericFlagSensorState = GenericFlagSensorState(state: sensorState) else {
32 | return nil
33 | }
34 |
35 | self.config = config
36 | self.state = state
37 |
38 | super.init(identifier: sensor.identifier, uniqueId: sensor.uniqueId, name: sensor.name, type: sensor.type, modelId: sensor.modelId, manufacturerName: sensor.manufacturerName, swVersion: sensor.swVersion, recycle: sensor.recycle)
39 | }
40 |
41 | public required init?(json: JSON) {
42 |
43 | guard let config: GenericFlagSensorConfig = "config" <~~ json else {
44 | return nil
45 | }
46 |
47 | guard let state: GenericFlagSensorState = "state" <~~ json else {
48 | return nil
49 | }
50 |
51 | self.config = config
52 | self.state = state
53 |
54 | super.init(json: json)
55 | }
56 | }
57 |
58 | public func ==(lhs: GenericFlagSensor, rhs: GenericFlagSensor) -> Bool {
59 | return lhs.identifier == rhs.identifier &&
60 | lhs.name == rhs.name &&
61 | lhs.state == rhs.state &&
62 | lhs.config == rhs.config &&
63 | lhs.type == rhs.type &&
64 | lhs.modelId == rhs.modelId &&
65 | lhs.manufacturerName == rhs.manufacturerName &&
66 | lhs.swVersion == rhs.swVersion
67 | }
68 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/GenericFlagSensor/GenericFlagSensorConfig.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GenericFlagSensorConfig.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class GenericFlagSensorConfig: PartialSensorConfig {
13 |
14 | init?(sensorConfig: SensorConfig) {
15 |
16 | super.init(on: sensorConfig.on, reachable: sensorConfig.reachable, battery: sensorConfig.battery, url: sensorConfig.url)
17 | }
18 |
19 | required public init?(json: JSON) {
20 | super.init(json: json)
21 | }
22 |
23 | }
24 |
25 | public func ==(lhs: GenericFlagSensorConfig, rhs: GenericFlagSensorConfig) -> Bool {
26 | return lhs.on == rhs.on &&
27 | lhs.reachable == rhs.reachable &&
28 | lhs.battery == rhs.battery &&
29 | lhs.url == rhs.url
30 | }
31 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/GenericFlagSensor/GenericFlagSensorState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GenericFlagSensorState.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class GenericFlagSensorState: PartialSensorState {
13 |
14 | public let flag: Bool
15 |
16 | init?(state: SensorState) {
17 |
18 | guard let flag: Bool = state.flag else {
19 | print("Can't create GenericFlagSensorState, missing required attribute \"flag\""); return nil
20 | }
21 |
22 | self.flag = flag
23 |
24 | super.init(lastUpdated: state.lastUpdated)
25 | }
26 |
27 | required public init?(json: JSON) {
28 |
29 | guard let flag: Bool = "flag" <~~ json else {
30 | print("Can't create GenericFlagSensorState, missing required attribute \"flag\" in JSON:\n \(json)"); return nil
31 | }
32 |
33 | self.flag = flag
34 |
35 | super.init(json: json)
36 | }
37 |
38 | public override func toJSON() -> JSON? {
39 |
40 | if var superJson = super.toJSON() {
41 | let json = jsonify([
42 | "flag" ~~> flag
43 | ])
44 | superJson.unionInPlace(json!)
45 | return superJson
46 | }
47 |
48 | return nil
49 | }
50 |
51 | }
52 |
53 | public func ==(lhs: GenericFlagSensorState, rhs: GenericFlagSensorState) -> Bool {
54 | return lhs.lastUpdated == rhs.lastUpdated &&
55 | lhs.flag == rhs.flag
56 | }
57 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/GenericStatusSensor/GenericStatusSensor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GenericStatusSensor.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class GenericStatusSensor: PartialSensor {
13 |
14 | let config: GenericStatusSensorConfig
15 | let state: GenericStatusSensorState
16 |
17 | required public init?(sensor: Sensor) {
18 |
19 | guard let sensorConfig = sensor.config else {
20 | return nil
21 | }
22 |
23 | guard let sensorState = sensor.state else {
24 | return nil
25 | }
26 |
27 | guard let config: GenericStatusSensorConfig = GenericStatusSensorConfig(sensorConfig: sensorConfig) else {
28 | return nil
29 | }
30 |
31 | guard let state: GenericStatusSensorState = GenericStatusSensorState(state: sensorState) else {
32 | return nil
33 | }
34 |
35 | self.config = config
36 | self.state = state
37 |
38 | super.init(identifier: sensor.identifier, uniqueId: sensor.uniqueId, name: sensor.name, type: sensor.type, modelId: sensor.modelId, manufacturerName: sensor.manufacturerName, swVersion: sensor.swVersion, recycle: sensor.recycle)
39 | }
40 |
41 | public required init?(json: JSON) {
42 |
43 | guard let config: GenericStatusSensorConfig = "config" <~~ json else {
44 | return nil
45 | }
46 |
47 | guard let state: GenericStatusSensorState = "state" <~~ json else {
48 | return nil
49 | }
50 |
51 | self.config = config
52 | self.state = state
53 |
54 | super.init(json: json)
55 | }
56 | }
57 |
58 | public func ==(lhs: GenericStatusSensor, rhs: GenericStatusSensor) -> Bool {
59 | return lhs.identifier == rhs.identifier &&
60 | lhs.name == rhs.name &&
61 | lhs.state == rhs.state &&
62 | lhs.config == rhs.config &&
63 | lhs.type == rhs.type &&
64 | lhs.modelId == rhs.modelId &&
65 | lhs.manufacturerName == rhs.manufacturerName &&
66 | lhs.swVersion == rhs.swVersion
67 | }
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/GenericStatusSensor/GenericStatusSensorConfig.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GenericStatusSensorConfig.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class GenericStatusSensorConfig: PartialSensorConfig {
13 |
14 | init?(sensorConfig: SensorConfig) {
15 |
16 | super.init(on: sensorConfig.on, reachable: sensorConfig.reachable, battery: sensorConfig.battery, url: sensorConfig.url)
17 | }
18 |
19 | required public init?(json: JSON) {
20 |
21 | super.init(json: json)
22 | }
23 | }
24 |
25 | public func ==(lhs: GenericStatusSensorConfig, rhs: GenericStatusSensorConfig) -> Bool {
26 | return lhs.on == rhs.on &&
27 | lhs.reachable == rhs.reachable &&
28 | lhs.battery == rhs.battery &&
29 | lhs.url == rhs.url
30 | }
31 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/GenericStatusSensor/GenericStatusSensorState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GenericStatusState.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class GenericStatusSensorState: PartialSensorState {
13 |
14 | public let status: Int
15 |
16 | init?(state: SensorState) {
17 |
18 | guard let status: Int = state.status else {
19 | print("Can't create GenericStatusState, missing required attribute \"status\""); return nil
20 | }
21 |
22 | self.status = status
23 |
24 | super.init(lastUpdated: state.lastUpdated)
25 | }
26 |
27 | required public init?(json: JSON) {
28 |
29 | guard let status: Int = "status" <~~ json else {
30 | print("Can't create GenericStatusState, missing required attribute \"status\" in JSON:\n \(json)"); return nil
31 | }
32 |
33 | self.status = status
34 |
35 | super.init(json: json)
36 | }
37 |
38 | public override func toJSON() -> JSON? {
39 |
40 | if var superJson = super.toJSON() {
41 | let json = jsonify([
42 | "status" ~~> status
43 | ])
44 | superJson.unionInPlace(json!)
45 | return superJson
46 | }
47 |
48 | return nil
49 | }
50 | }
51 |
52 | public func ==(lhs: GenericStatusSensorState, rhs: GenericStatusSensorState) -> Bool {
53 | return lhs.lastUpdated == rhs.lastUpdated &&
54 | lhs.status == rhs.status
55 | }
56 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/HumiditySensor/HumiditySensor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Humidity.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class HumiditySensor: PartialSensor {
13 |
14 | let config: HumiditySensorConfig
15 | let state: HumiditySensorState
16 |
17 | required public init?(sensor: Sensor) {
18 |
19 | guard let sensorConfig = sensor.config else {
20 | return nil
21 | }
22 |
23 | guard let sensorState = sensor.state else {
24 | return nil
25 | }
26 |
27 | guard let config: HumiditySensorConfig = HumiditySensorConfig(sensorConfig: sensorConfig) else {
28 | return nil
29 | }
30 |
31 | guard let state: HumiditySensorState = HumiditySensorState(state: sensorState) else {
32 | return nil
33 | }
34 |
35 | self.config = config
36 | self.state = state
37 |
38 | super.init(identifier: sensor.identifier, uniqueId: sensor.uniqueId, name: sensor.name, type: sensor.type, modelId: sensor.modelId, manufacturerName: sensor.manufacturerName, swVersion: sensor.swVersion, recycle: sensor.recycle)
39 | }
40 |
41 | public required init?(json: JSON) {
42 |
43 | guard let config: HumiditySensorConfig = "config" <~~ json else {
44 | return nil
45 | }
46 |
47 | guard let state: HumiditySensorState = "state" <~~ json else {
48 | return nil
49 | }
50 |
51 | self.config = config
52 | self.state = state
53 |
54 | super.init(json: json)
55 | }
56 | }
57 |
58 | public func ==(lhs: HumiditySensor, rhs: HumiditySensor) -> Bool {
59 | return lhs.identifier == rhs.identifier &&
60 | lhs.name == rhs.name &&
61 | lhs.state == rhs.state &&
62 | lhs.config == rhs.config &&
63 | lhs.type == rhs.type &&
64 | lhs.modelId == rhs.modelId &&
65 | lhs.manufacturerName == rhs.manufacturerName &&
66 | lhs.swVersion == rhs.swVersion
67 | }
68 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/HumiditySensor/HumiditySensorConfig.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HumiditySensorConfig.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class HumiditySensorConfig: PartialSensorConfig {
13 |
14 | init?(sensorConfig: SensorConfig) {
15 |
16 | super.init(on: sensorConfig.on, reachable: sensorConfig.reachable, battery: sensorConfig.battery, url: sensorConfig.url)
17 | }
18 |
19 | required public init?(json: JSON) {
20 | super.init(json: json)
21 | }
22 | }
23 |
24 | public func ==(lhs: HumiditySensorConfig, rhs: HumiditySensorConfig) -> Bool {
25 | return lhs.on == rhs.on &&
26 | lhs.reachable == rhs.reachable &&
27 | lhs.battery == rhs.battery &&
28 | lhs.url == rhs.url
29 | }
30 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/HumiditySensor/HumiditySensorState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HumiditySensorState.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class HumiditySensorState: PartialSensorState {
13 |
14 | public let humidity: Int
15 |
16 | init?(state: SensorState) {
17 |
18 | guard let humidity: Int = state.humidity else {
19 | print("Can't create HumiditySensorState, missing required attribute \"humidity\""); return nil
20 | }
21 |
22 | self.humidity = humidity
23 |
24 | super.init(lastUpdated: state.lastUpdated)
25 | }
26 |
27 | required public init?(json: JSON) {
28 |
29 | guard let humidity: Int = "humidity" <~~ json else {
30 | print("Can't create HumiditySensorState, missing required attribute \"humidity\" in JSON:\n \(json)"); return nil
31 | }
32 |
33 | self.humidity = humidity
34 |
35 | super.init(json: json)
36 | }
37 |
38 | public override func toJSON() -> JSON? {
39 |
40 | if var superJson = super.toJSON() {
41 | let json = jsonify([
42 | "humidity" ~~> self.humidity
43 | ])
44 | superJson.unionInPlace(json!)
45 | return superJson
46 | }
47 |
48 | return nil
49 | }
50 | }
51 |
52 | public func ==(lhs: HumiditySensorState, rhs: HumiditySensorState) -> Bool {
53 | return lhs.lastUpdated == rhs.lastUpdated &&
54 | lhs.humidity == rhs.humidity
55 | }
56 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/LightLevelSensor/LightLevelSensor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LightLevelSensor.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 08.11.19.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class LightLevelSensor: PartialSensor {
13 |
14 | let config: LightLevelSensorConfig
15 | let state: LightLevelSensorState
16 |
17 | required public init?(sensor: Sensor) {
18 |
19 | guard let sensorConfig = sensor.config else {
20 | return nil
21 | }
22 |
23 | guard let sensorState = sensor.state else {
24 | return nil
25 | }
26 |
27 | guard let config: LightLevelSensorConfig = LightLevelSensorConfig(sensorConfig: sensorConfig) else {
28 | return nil
29 | }
30 |
31 | guard let state: LightLevelSensorState = LightLevelSensorState(state: sensorState) else {
32 | return nil
33 | }
34 |
35 | self.config = config
36 | self.state = state
37 |
38 | super.init(identifier: sensor.identifier, uniqueId: sensor.uniqueId, name: sensor.name, type: sensor.type, modelId: sensor.modelId, manufacturerName: sensor.manufacturerName, swVersion: sensor.swVersion, recycle: sensor.recycle)
39 | }
40 |
41 | public required init?(json: JSON) {
42 |
43 | guard let config: LightLevelSensorConfig = "config" <~~ json else {
44 | return nil
45 | }
46 |
47 | guard let state: LightLevelSensorState = "state" <~~ json else {
48 | return nil
49 | }
50 |
51 | self.config = config
52 | self.state = state
53 |
54 | super.init(json: json)
55 | }
56 | }
57 |
58 | public func ==(lhs: LightLevelSensor, rhs: LightLevelSensor) -> Bool {
59 | return lhs.identifier == rhs.identifier &&
60 | lhs.name == rhs.name &&
61 | lhs.state == rhs.state &&
62 | lhs.config == rhs.config &&
63 | lhs.type == rhs.type &&
64 | lhs.modelId == rhs.modelId &&
65 | lhs.manufacturerName == rhs.manufacturerName &&
66 | lhs.swVersion == rhs.swVersion
67 | }
68 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/LightLevelSensor/LightLevelSensorConfig.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LightLevelSensorConfig.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 08.11.19.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class LightLevelSensorConfig: PartialSensorConfig {
13 |
14 | /**
15 | Threshold the user configured to be used in rules to determine insufficient lightlevel (ie below threshold). Default value 16000
16 | */
17 | public let tholddark: Int
18 |
19 | /**
20 | Threshold the user configured to be used in rules to determine sufficient lightlevel (ie above threshold). Specified as relative offset to the “dark” threshold. Shall be >=1. Default value 7000
21 | */
22 | public let tholdoffset: Int
23 |
24 | init?(sensorConfig: SensorConfig) {
25 |
26 | guard let tholddark: Int = sensorConfig.tholddark else {
27 | print("Can't create LightlevelSensorConfig, missing required attribute \"tholddark\""); return nil
28 | }
29 | self.tholddark = tholddark
30 |
31 | guard let tholdoffset: Int = sensorConfig.tholdoffset else {
32 | print("Can't create LightlevelSensorConfig, missing required attribute \"tholdoffset\""); return nil
33 | }
34 | self.tholdoffset = tholdoffset
35 |
36 | super.init(on: sensorConfig.on, reachable: sensorConfig.reachable, battery: sensorConfig.battery, url: sensorConfig.url)
37 | }
38 |
39 | required public init?(json: JSON) {
40 |
41 | guard let tholddark: Int = "tholddark" <~~ json else {
42 | print("Can't create LightlevelSensorConfig, missing required attribute \"tholddark\""); return nil
43 | }
44 | self.tholddark = tholddark
45 |
46 | guard let tholdoffset: Int = "tholdoffset" <~~ json else {
47 | print("Can't create LightlevelSensorConfig, missing required attribute \"tholdoffset\""); return nil
48 | }
49 | self.tholdoffset = tholdoffset
50 |
51 | super.init(json: json)
52 | }
53 |
54 | public override func toJSON() -> JSON? {
55 |
56 | if var superJson = super.toJSON() {
57 | let json = jsonify([
58 | "tholddark" ~~> tholddark,
59 | "tholdoffset" ~~> tholdoffset
60 | ])
61 | superJson.unionInPlace(json!)
62 | return superJson
63 | }
64 |
65 | return nil
66 | }
67 | }
68 |
69 | public func ==(lhs: LightLevelSensorConfig, rhs: LightLevelSensorConfig) -> Bool {
70 | return lhs.on == rhs.on &&
71 | lhs.reachable == rhs.reachable &&
72 | lhs.battery == rhs.battery &&
73 | lhs.url == rhs.url &&
74 | lhs.tholddark == rhs.tholddark &&
75 | lhs.tholdoffset == rhs.tholdoffset
76 | }
77 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/LightLevelSensor/LightLevelSensorState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LightlevelSensorState.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 08.11.19.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class LightLevelSensorState: PartialSensorState {
13 |
14 | public let lightlevel: Int?
15 | public let dark: Bool?
16 | public let daylight: Bool?
17 |
18 | init?(state: SensorState) {
19 |
20 | self.lightlevel = state.lightlevel
21 | self.dark = state.dark
22 | self.daylight = state.daylight
23 |
24 | super.init(lastUpdated: state.lastUpdated)
25 | }
26 |
27 | required public init?(json: JSON) {
28 |
29 | guard let lightlevel: Int = "lightlevel" <~~ json else {
30 | print("Can't create LightlevelSensorState, missing required attribute \"lightlevel\" in JSON:\n \(json)"); return nil
31 | }
32 | self.lightlevel = lightlevel
33 |
34 | guard let dark: Bool = "dark" <~~ json else {
35 | print("Can't create LightlevelSensorState, missing required attribute \"dark\" in JSON:\n \(json)"); return nil
36 | }
37 | self.dark = dark
38 |
39 | guard let daylight: Bool = "daylight" <~~ json else {
40 | print("Can't create LightlevelSensorState, missing required attribute \"daylight\" in JSON:\n \(json)"); return nil
41 | }
42 | self.daylight = daylight
43 |
44 | super.init(json: json)
45 | }
46 |
47 | public override func toJSON() -> JSON? {
48 |
49 | if var superJson = super.toJSON() {
50 | let json = jsonify([
51 | "lightlevel" ~~> self.lightlevel,
52 | "dark" ~~> self.dark,
53 | "daylight" ~~> self.daylight
54 | ])
55 | superJson.unionInPlace(json!)
56 | return superJson
57 | }
58 |
59 | return nil
60 | }
61 | }
62 |
63 | public func ==(lhs: LightLevelSensorState, rhs: LightLevelSensorState) -> Bool {
64 | return lhs.lastUpdated == rhs.lastUpdated &&
65 | lhs.lightlevel == rhs.lightlevel &&
66 | lhs.dark == lhs.dark &&
67 | lhs.daylight == lhs.daylight
68 | }
69 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/OpenCloseSensor/OpenCloseSensor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OpenCloseSensor.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class OpenCloseSensor: PartialSensor {
13 |
14 | let config: OpenCloseSensorConfig
15 | let state: OpenCloseSensorState
16 |
17 | required public init?(sensor: Sensor) {
18 |
19 | guard let sensorConfig = sensor.config else {
20 | return nil
21 | }
22 |
23 | guard let sensorState = sensor.state else {
24 | return nil
25 | }
26 |
27 | let config: OpenCloseSensorConfig = OpenCloseSensorConfig(sensorConfig: sensorConfig)
28 |
29 | guard let state: OpenCloseSensorState = OpenCloseSensorState(state: sensorState) else {
30 | return nil
31 | }
32 |
33 | self.config = config
34 | self.state = state
35 |
36 | super.init(identifier: sensor.identifier, uniqueId: sensor.uniqueId, name: sensor.name, type: sensor.type, modelId: sensor.modelId, manufacturerName: sensor.manufacturerName, swVersion: sensor.swVersion, recycle: sensor.recycle)
37 | }
38 |
39 | public required init?(json: JSON) {
40 |
41 | guard let config: OpenCloseSensorConfig = "config" <~~ json else {
42 | return nil
43 | }
44 |
45 | guard let state: OpenCloseSensorState = "state" <~~ json else {
46 | return nil
47 | }
48 |
49 | self.config = config
50 | self.state = state
51 |
52 | super.init(json: json)
53 | }
54 | }
55 |
56 | public func ==(lhs: OpenCloseSensor, rhs: OpenCloseSensor) -> Bool {
57 | return lhs.identifier == rhs.identifier &&
58 | lhs.name == rhs.name &&
59 | lhs.state == rhs.state &&
60 | lhs.config == rhs.config &&
61 | lhs.type == rhs.type &&
62 | lhs.modelId == rhs.modelId &&
63 | lhs.manufacturerName == rhs.manufacturerName &&
64 | lhs.swVersion == rhs.swVersion
65 | }
66 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/OpenCloseSensor/OpenCloseSensorConfig.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OpenCloseSensorConfig.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class OpenCloseSensorConfig: PartialSensorConfig {
13 |
14 | init(sensorConfig: SensorConfig) {
15 |
16 | super.init(on: sensorConfig.on, reachable: sensorConfig.reachable, battery: sensorConfig.battery, url: sensorConfig.url)
17 | }
18 |
19 | required public init?(json: JSON) {
20 | super.init(json: json)
21 | }
22 | }
23 |
24 | public func ==(lhs: OpenCloseSensorConfig, rhs: OpenCloseSensorConfig) -> Bool {
25 | return lhs.on == rhs.on &&
26 | lhs.reachable == rhs.reachable &&
27 | lhs.battery == rhs.battery &&
28 | lhs.url == rhs.url
29 | }
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/OpenCloseSensor/OpenCloseSensorState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OpenCloseSensorState.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class OpenCloseSensorState: PartialSensorState {
13 |
14 | public let open: Bool
15 |
16 | init?(state: SensorState) {
17 |
18 | guard let open: Bool = state.open else {
19 | print("Can't create OpenCloseSensorState, missing required attribute \"open\""); return nil
20 | }
21 |
22 | self.open = open
23 |
24 | super.init(lastUpdated: state.lastUpdated)
25 | }
26 |
27 | required public init?(json: JSON) {
28 |
29 | guard let open: Bool = "open" <~~ json else {
30 | print("Can't create OpenCloseSensorState, missing required attribute \"open\" in JSON:\n \(json)"); return nil
31 | }
32 |
33 | self.open = open
34 |
35 | super.init(json: json)
36 | }
37 |
38 | public override func toJSON() -> JSON? {
39 |
40 | if var superJson = super.toJSON() {
41 | let json = jsonify([
42 | "open" ~~> self.open
43 | ])
44 | superJson.unionInPlace(json!)
45 | return superJson
46 | }
47 |
48 | return nil
49 | }
50 | }
51 |
52 | public func ==(lhs: OpenCloseSensorState, rhs: OpenCloseSensorState) -> Bool {
53 | return lhs.lastUpdated == rhs.lastUpdated &&
54 | lhs.open == rhs.open
55 | }
56 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/PresenceSensor/PresenceSensor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PresenceSensor.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class PresenceSensor: PartialSensor {
13 |
14 | let config: PresenceSensorConfig
15 | let state: PresenceSensorState
16 |
17 | required public init?(sensor: Sensor) {
18 |
19 | guard let sensorConfig = sensor.config else {
20 | return nil
21 | }
22 |
23 | guard let sensorState = sensor.state else {
24 | return nil
25 | }
26 |
27 | let config: PresenceSensorConfig = PresenceSensorConfig(sensorConfig: sensorConfig)
28 |
29 | guard let state: PresenceSensorState = PresenceSensorState(state: sensorState) else {
30 | return nil
31 | }
32 |
33 | self.config = config
34 | self.state = state
35 |
36 | super.init(identifier: sensor.identifier, uniqueId: sensor.uniqueId, name: sensor.name, type: sensor.type, modelId: sensor.modelId, manufacturerName: sensor.manufacturerName, swVersion: sensor.swVersion, recycle: sensor.recycle)
37 | }
38 |
39 | public required init?(json: JSON) {
40 |
41 | guard let config: PresenceSensorConfig = "config" <~~ json else {
42 | return nil
43 | }
44 |
45 | guard let state: PresenceSensorState = "state" <~~ json else {
46 | return nil
47 | }
48 |
49 | self.config = config
50 | self.state = state
51 |
52 | super.init(json: json)
53 | }
54 | }
55 |
56 | public func ==(lhs: PresenceSensor, rhs: PresenceSensor) -> Bool {
57 | return lhs.identifier == rhs.identifier &&
58 | lhs.name == rhs.name &&
59 | lhs.state == rhs.state &&
60 | lhs.config == rhs.config &&
61 | lhs.type == rhs.type &&
62 | lhs.modelId == rhs.modelId &&
63 | lhs.manufacturerName == rhs.manufacturerName &&
64 | lhs.swVersion == rhs.swVersion
65 | }
66 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/PresenceSensor/PresenceSensorConfig.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PresenceSensorConfig.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class PresenceSensorConfig: PartialSensorConfig {
13 |
14 | init(sensorConfig: SensorConfig) {
15 |
16 | super.init(on: sensorConfig.on, reachable: sensorConfig.reachable, battery: sensorConfig.battery, url: sensorConfig.url)
17 | }
18 |
19 | required public init?(json: JSON) {
20 | super.init(json: json)
21 | }
22 | }
23 |
24 | public func ==(lhs: PresenceSensorConfig, rhs: PresenceSensorConfig) -> Bool {
25 | return lhs.on == rhs.on &&
26 | lhs.reachable == rhs.reachable &&
27 | lhs.battery == rhs.battery &&
28 | lhs.url == rhs.url
29 | }
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/PresenceSensor/PresenceSensorState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PresenceSensorState.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class PresenceSensorState: PartialSensorState {
13 |
14 | public let presence: Bool
15 |
16 | init?(state: SensorState) {
17 |
18 | guard let presence: Bool = state.presence else {
19 | print("Can't create PresenceSensorState, missing required attribute \"presence\""); return nil
20 | }
21 |
22 | self.presence = presence
23 |
24 | super.init(lastUpdated: state.lastUpdated)
25 | }
26 |
27 | required public init?(json: JSON) {
28 |
29 | guard let presence: Bool = "presence" <~~ json else {
30 | print("Can't create PresenceSensorState, missing required attribute \"presence\" in JSON:\n \(json)"); return nil
31 | }
32 |
33 | self.presence = presence
34 |
35 | super.init(json: json)
36 | }
37 |
38 | public override func toJSON() -> JSON? {
39 |
40 | if var superJson = super.toJSON() {
41 | let json = jsonify([
42 | "presence" ~~> self.presence
43 | ])
44 | superJson.unionInPlace(json!)
45 | return superJson
46 | }
47 |
48 | return nil
49 | }
50 | }
51 |
52 | public func ==(lhs: PresenceSensorState, rhs: PresenceSensorState) -> Bool {
53 | return lhs.lastUpdated == rhs.lastUpdated &&
54 | lhs.presence == rhs.presence
55 | }
56 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/SensorConfig.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SensorConfig.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public enum SensorAlertMode {
13 | case unknown, // It is unkown what the current alert value is
14 | none, // No alert active
15 | select, // Select alert (1 indication cycle) is active
16 | lSelect // Select alert (30 seconds of indication cycles) is active
17 | }
18 |
19 | public class PartialSensorConfig: JSONDecodable {
20 |
21 | public var on: Bool
22 | public var reachable: Bool?
23 | public var battery: Int?
24 | public var url: String?
25 |
26 | init(on: Bool, reachable: Bool?, battery: Int?, url: String?) {
27 |
28 | self.on = on
29 | self.reachable = reachable
30 | self.battery = battery
31 | self.url = url
32 | }
33 |
34 | required public init?(json: JSON) {
35 |
36 | guard let on: Bool = "on" <~~ json else {
37 | print("Can't create SensorConfig, missing required attribute \"on\" in JSON:\n \(json)"); return nil
38 | }
39 |
40 | self.on = on
41 | self.reachable = "reachable" <~~ json
42 | self.battery = "battery" <~~ json
43 | self.url = "url" <~~ json
44 |
45 | }
46 |
47 | public func toJSON() -> JSON? {
48 |
49 | let json = jsonify([
50 | "on" ~~> on,
51 | "reachable" ~~> reachable,
52 | "battery" ~~> battery,
53 | "url" ~~> url
54 | ])
55 |
56 | return json
57 | }
58 | }
59 |
60 | public class SensorConfig: PartialSensorConfig {
61 |
62 | // DaylightSensorConfig
63 | public let long: String?
64 | public let lat: String?
65 | public let sunriseOffset: Int?
66 | public let sunsetOffset: Int?
67 |
68 | // LightlevelSensorConfig
69 | public let tholddark: Int?
70 | public let tholdoffset: Int?
71 |
72 | required public init?(json: JSON) {
73 |
74 | long = "long" <~~ json
75 | lat = "lat" <~~ json
76 | sunriseOffset = "sunriseoffset" <~~ json
77 | sunsetOffset = "sunsetoffset" <~~ json
78 | tholddark = "tholddark" <~~ json
79 | tholdoffset = "tholdoffset" <~~ json
80 |
81 | super.init(json: json)
82 | }
83 |
84 | public override func toJSON() -> JSON? {
85 |
86 | let json = jsonify([
87 | "on" ~~> on,
88 | "reachable" ~~> reachable,
89 | "battery" ~~> battery,
90 | "url" ~~> url,
91 | "long" ~~> long,
92 | "lat" ~~> lat,
93 | "sunriseoffset" ~~> sunriseOffset,
94 | "sunsetoffset" ~~> sunsetOffset,
95 | "tholddark" ~~> tholddark,
96 | "tholdoffset" ~~> tholdoffset
97 | ])
98 |
99 | return json
100 | }
101 | }
102 |
103 |
104 | extension SensorConfig: Hashable {
105 |
106 | public func hash(into hasher: inout Hasher) {
107 |
108 | hasher.combine(1)
109 | }
110 | }
111 |
112 | public func ==(lhs: SensorConfig, rhs: SensorConfig) -> Bool {
113 | return lhs.on == rhs.on &&
114 | lhs.reachable == rhs.reachable &&
115 | lhs.battery == rhs.battery &&
116 | lhs.url == rhs.url &&
117 | lhs.long == rhs.long &&
118 | lhs.lat == rhs.lat &&
119 | lhs.sunriseOffset == rhs.sunriseOffset &&
120 | lhs.sunsetOffset == rhs.sunsetOffset &&
121 | lhs.tholddark == rhs.tholddark &&
122 | lhs.tholdoffset == rhs.tholdoffset
123 | }
124 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/SensorState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SensorState.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public enum ButtonEvent: Int {
13 | /**
14 | Tap Button 1
15 | */
16 | case button_1 = 34
17 | /**
18 | Tap Button 2
19 | */
20 | case button_2 = 16
21 | /**
22 | Tap Button 3
23 | */
24 | case button_3 = 17
25 | /**
26 | Tap Button 4
27 | */
28 | case button_4 = 18
29 | /**
30 | INITIAL_PRESS Button 1 (ON)
31 | */
32 | case initial_PRESS_BUTTON_1 = 1000
33 | /**
34 | HOLD Button 1 (ON)
35 | */
36 | case hold_BUTTON_1 = 1001
37 | /**
38 | SHORT_RELEASED Button 1
39 | */
40 | case short_RELEASED_BUTTON_1 = 1002
41 | /**
42 | LONG_RELEASED Button 1
43 | */
44 | case long_RELEASED_BUTTON_1 = 1003
45 | /**
46 | INITIAL_PRESS Button 2 (ON)
47 | */
48 | case initial_PRESS_BUTTON_2 = 2000
49 | /**
50 | HOLD Button 2 (ON)
51 | */
52 | case hold_BUTTON_2 = 2001
53 | /**
54 | SHORT_RELEASED Button 2
55 | */
56 | case short_RELEASED_BUTTON_2 = 2002
57 | /**
58 | LONG_RELEASED Button 2
59 | */
60 | case long_RELEASED_BUTTON_2 = 2003
61 | /**
62 | INITIAL_PRESS Button 3 (ON)
63 | */
64 | case initial_PRESS_BUTTON_3 = 3000
65 | /**
66 | HOLD Button 3 (ON)
67 | */
68 | case hold_BUTTON_3 = 3001
69 | /**
70 | SHORT_RELEASED Button 3
71 | */
72 | case short_RELEASED_BUTTON_3 = 3002
73 | /**
74 | LONG_RELEASED Button 3
75 | */
76 | case long_RELEASED_BUTTON_3 = 3003
77 | /**
78 | INITIAL_PRESS Button 4 (ON)
79 | */
80 | case initial_PRESS_BUTTON_4 = 4000
81 | /**
82 | HOLD Button 4 (ON)
83 | */
84 | case hold_BUTTON_4 = 4001
85 | /**
86 | SHORT_RELEASED Button 4
87 | */
88 | case short_RELEASED_BUTTON_4 = 4002
89 | /**
90 | LONG_RELEASED Button 4
91 | */
92 | case long_RELEASED_BUTTON_4 = 4003
93 | }
94 |
95 | public func ==(lhs: PartialSensorState, rhs: PartialSensorState) -> Bool {
96 | return lhs.lastUpdated == rhs.lastUpdated
97 | }
98 |
99 | public class PartialSensorState: JSONDecodable, Equatable {
100 |
101 | public let lastUpdated: Date?
102 |
103 | init(lastUpdated: Date?) {
104 | self.lastUpdated = lastUpdated
105 | }
106 |
107 | required public init?(json: JSON) {
108 |
109 | let dateFormatter = DateFormatter.hueApiDateFormatter
110 |
111 | lastUpdated = Decoder.decode(dateForKey: "lastupdated", dateFormatter: dateFormatter)(json)
112 | }
113 |
114 | public func toJSON() -> JSON? {
115 |
116 | let dateFormatter = DateFormatter.hueApiDateFormatter
117 |
118 | let json = jsonify([
119 | Encoder.encode(dateForKey: "lastupdated", dateFormatter: dateFormatter)(lastUpdated)
120 | ])
121 |
122 | return json
123 | }
124 | }
125 |
126 | public class SensorState: PartialSensorState {
127 |
128 | // Daylight
129 | public let daylight: Bool?
130 |
131 | // GenericFlagSensor
132 | public let flag: Bool?
133 |
134 | // GenericStatusState
135 | public let status: Int?
136 |
137 | // HumiditySensorState
138 | public let humidity: Int?
139 |
140 | // OpenCloseSensorState
141 | public let open: Bool?
142 |
143 | // PresenceSensorState
144 | public let presence: Bool?
145 |
146 | // SwitchSensorState
147 | public let buttonEvent: ButtonEvent?
148 |
149 | // TemperatureSensorState
150 | public let temperature: Int?
151 |
152 | // LightlevelSensorState
153 | public let lightlevel: Int?
154 | public let dark: Bool?
155 |
156 | required public init?(json: JSON) {
157 |
158 | daylight = "daylight" <~~ json
159 | flag = "flag" <~~ json
160 | status = "status" <~~ json
161 | humidity = "humidity" <~~ json
162 | open = "open" <~~ json
163 | presence = "presence" <~~ json
164 | buttonEvent = "buttonevent" <~~ json
165 | temperature = "temperature" <~~ json
166 | lightlevel = "lightlevel" <~~ json
167 | dark = "dark" <~~ json
168 |
169 | super.init(json: json)
170 | }
171 |
172 | public override func toJSON() -> JSON? {
173 |
174 | let json = jsonify([
175 | "daylight" ~~> daylight,
176 | "flag" ~~> flag,
177 | "status" ~~> status,
178 | "humidity" ~~> humidity,
179 | "open" ~~> open,
180 | "presence" ~~> presence,
181 | "buttonevent" ~~> buttonEvent,
182 | "temperature" ~~> temperature,
183 | "lightlevel" ~~> lightlevel,
184 | "dark" ~~> dark
185 | ])
186 |
187 | return json
188 | }
189 |
190 | }
191 |
192 |
193 | public func ==(lhs: SensorState, rhs: SensorState) -> Bool {
194 | return lhs.lastUpdated == rhs.lastUpdated &&
195 | lhs.daylight == rhs.daylight &&
196 | lhs.flag == rhs.flag &&
197 | lhs.status == rhs.status &&
198 | lhs.open == rhs.open &&
199 | lhs.presence == rhs.presence &&
200 | lhs.buttonEvent == rhs.buttonEvent &&
201 | lhs.temperature == rhs.temperature &&
202 | lhs.lightlevel == rhs.lightlevel &&
203 | lhs.dark == rhs.dark
204 | }
205 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/SwitchSensor/SwitchSensor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwitchSensor.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class SwitchSensor: PartialSensor {
13 |
14 | let config: SwitchSensorConfig
15 | let state: SwitchSensorState
16 |
17 | required public init?(sensor: Sensor) {
18 |
19 | guard let sensorConfig = sensor.config else {
20 | return nil
21 | }
22 |
23 | guard let sensorState = sensor.state else {
24 | return nil
25 | }
26 |
27 | guard let config: SwitchSensorConfig = SwitchSensorConfig(sensorConfig: sensorConfig) else {
28 | return nil
29 | }
30 |
31 | guard let state: SwitchSensorState = SwitchSensorState(state: sensorState) else {
32 | return nil
33 | }
34 |
35 | self.config = config
36 | self.state = state
37 |
38 | super.init(identifier: sensor.identifier, uniqueId: sensor.uniqueId, name: sensor.name, type: sensor.type, modelId: sensor.modelId, manufacturerName: sensor.manufacturerName, swVersion: sensor.swVersion, recycle: sensor.recycle)
39 | }
40 |
41 | public required init?(json: JSON) {
42 |
43 | guard let config: SwitchSensorConfig = "config" <~~ json else {
44 | return nil
45 | }
46 |
47 | guard let state: SwitchSensorState = "state" <~~ json else {
48 | return nil
49 | }
50 |
51 | self.config = config
52 | self.state = state
53 |
54 | super.init(json: json)
55 | }
56 | }
57 |
58 | public func ==(lhs: SwitchSensor, rhs: SwitchSensor) -> Bool {
59 | return lhs.identifier == rhs.identifier &&
60 | lhs.name == rhs.name &&
61 | lhs.state == rhs.state &&
62 | lhs.config == rhs.config &&
63 | lhs.type == rhs.type &&
64 | lhs.modelId == rhs.modelId &&
65 | lhs.manufacturerName == rhs.manufacturerName &&
66 | lhs.swVersion == rhs.swVersion
67 | }
68 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/SwitchSensor/SwitchSensorConfig.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwitchSensorConfig.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class SwitchSensorConfig: PartialSensorConfig {
13 |
14 | init?(sensorConfig: SensorConfig) {
15 |
16 | super.init(on: sensorConfig.on, reachable: sensorConfig.reachable, battery: sensorConfig.battery, url: sensorConfig.url)
17 | }
18 |
19 | required public init?(json: JSON) {
20 | super.init(json: json)
21 | }
22 | }
23 |
24 | public func ==(lhs: SwitchSensorConfig, rhs: SwitchSensorConfig) -> Bool {
25 | return lhs.on == rhs.on &&
26 | lhs.reachable == rhs.reachable &&
27 | lhs.battery == rhs.battery &&
28 | lhs.url == rhs.url
29 | }
30 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/SwitchSensor/SwitchSensorState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwitchSensorState.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 |
13 | public class SwitchSensorState: PartialSensorState {
14 |
15 | public let buttonEvent: ButtonEvent?
16 |
17 | init?(state: SensorState) {
18 |
19 | // guard let buttonEvent: ButtonEvent = state.buttonEvent else {
20 | // Log.error("Can't create SwitchSensorState, missing required attribute \"buttonevent\""); return nil
21 | // }
22 |
23 | self.buttonEvent = state.buttonEvent
24 |
25 | super.init(lastUpdated: state.lastUpdated)
26 | }
27 |
28 | required public init?(json: JSON) {
29 |
30 | // guard let buttonEvent: ButtonEvent = "buttonevent" <~~ json else {
31 | // Log.error("Can't create SwitchSensorState, missing required attribute \"buttonevent\" in JSON:\n \(json)"); return nil
32 | // }
33 |
34 | self.buttonEvent = "buttonevent" <~~ json
35 |
36 | super.init(json: json)
37 | }
38 |
39 | public override func toJSON() -> JSON? {
40 |
41 | if var superJson = super.toJSON() {
42 | let json = jsonify([
43 | "buttonevent" ~~> self.buttonEvent
44 | ])
45 | superJson.unionInPlace(json!)
46 | return superJson
47 | }
48 |
49 | return nil
50 | }
51 | }
52 |
53 | public func ==(lhs: SwitchSensorState, rhs: SwitchSensorState) -> Bool {
54 | return lhs.lastUpdated == rhs.lastUpdated &&
55 | lhs.buttonEvent == rhs.buttonEvent
56 | }
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/TemperatureSensor/TemperatureSensor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TemperatureSensor.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class TemperatureSensor: PartialSensor {
13 |
14 | let config: TemperatureSensorConfig
15 | let state: TemperatureSensorState
16 |
17 | required public init?(sensor: Sensor) {
18 |
19 | guard let sensorConfig = sensor.config else {
20 | return nil
21 | }
22 |
23 | guard let sensorState = sensor.state else {
24 | return nil
25 | }
26 |
27 | guard let config: TemperatureSensorConfig = TemperatureSensorConfig(sensorConfig: sensorConfig) else {
28 | return nil
29 | }
30 |
31 | guard let state: TemperatureSensorState = TemperatureSensorState(state: sensorState) else {
32 | return nil
33 | }
34 |
35 | self.config = config
36 | self.state = state
37 |
38 | super.init(identifier: sensor.identifier, uniqueId: sensor.uniqueId, name: sensor.name, type: sensor.type, modelId: sensor.modelId, manufacturerName: sensor.manufacturerName, swVersion: sensor.swVersion, recycle: sensor.recycle)
39 | }
40 |
41 | public required init?(json: JSON) {
42 |
43 | guard let config: TemperatureSensorConfig = "config" <~~ json else {
44 | return nil
45 | }
46 |
47 | guard let state: TemperatureSensorState = "state" <~~ json else {
48 | return nil
49 | }
50 |
51 | self.config = config
52 | self.state = state
53 |
54 | super.init(json: json)
55 | }
56 | }
57 |
58 | public func ==(lhs: TemperatureSensor, rhs: TemperatureSensor) -> Bool {
59 | return lhs.identifier == rhs.identifier &&
60 | lhs.name == rhs.name &&
61 | lhs.state == rhs.state &&
62 | lhs.config == rhs.config &&
63 | lhs.type == rhs.type &&
64 | lhs.modelId == rhs.modelId &&
65 | lhs.manufacturerName == rhs.manufacturerName &&
66 | lhs.swVersion == rhs.swVersion
67 | }
68 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/TemperatureSensor/TemperatureSensorConfig.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TemperatureSensorConfig.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class TemperatureSensorConfig: PartialSensorConfig {
13 |
14 | init?(sensorConfig: SensorConfig) {
15 |
16 | super.init(on: sensorConfig.on, reachable: sensorConfig.reachable, battery: sensorConfig.battery, url: sensorConfig.url)
17 | }
18 |
19 | required public init?(json: JSON) {
20 | super.init(json: json)
21 | }
22 | }
23 |
24 | public func ==(lhs: TemperatureSensorConfig, rhs: TemperatureSensorConfig) -> Bool {
25 | return lhs.on == rhs.on &&
26 | lhs.reachable == rhs.reachable &&
27 | lhs.battery == rhs.battery &&
28 | lhs.url == rhs.url
29 | }
30 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/Sensors/TemperatureSensor/TemperatureSensorState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TemperatureSensorState.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 01.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public class TemperatureSensorState: PartialSensorState {
13 |
14 | public let temperature: Int
15 |
16 | init?(state: SensorState) {
17 |
18 | guard let temperature: Int = state.temperature else {
19 | print("Can't create TemperatureSensorState, missing required attribute \"temperature\""); return nil
20 | }
21 |
22 | self.temperature = temperature
23 |
24 | super.init(lastUpdated: state.lastUpdated)
25 | }
26 |
27 | required public init?(json: JSON) {
28 |
29 | guard let temperature: Int = "temperature" <~~ json else {
30 | print("Can't create TemperatureSensorState, missing required attribute \"temperature\" in JSON:\n \(json)"); return nil
31 | }
32 |
33 | self.temperature = temperature
34 |
35 | super.init(json: json)
36 | }
37 |
38 | public override func toJSON() -> JSON? {
39 |
40 | if var superJson = super.toJSON() {
41 | let json = jsonify([
42 | "temperature" ~~> self.temperature
43 | ])
44 | superJson.unionInPlace(json!)
45 | return superJson
46 | }
47 |
48 | return nil
49 | }
50 | }
51 |
52 | public func ==(lhs: TemperatureSensorState, rhs: TemperatureSensorState) -> Bool {
53 | return lhs.lastUpdated == rhs.lastUpdated &&
54 | lhs.temperature == rhs.temperature
55 | }
56 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/SoftwareUpdateStatus.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SoftwareUpdateStatus.swift
3 | // Pods
4 | //
5 | // Created by Marcel Dittmann on 22.04.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public enum UpdateState: Int {
13 |
14 | case noUpdate, downloading, readyForInstall, installed
15 | }
16 |
17 | public struct SoftwareUpdateStatus: JSONDecodable {
18 |
19 | public let updatestate: UpdateState?
20 |
21 | /**
22 | Check for update flag of the bridge
23 | */
24 | public let checkforupdate: Bool?
25 |
26 | /**
27 | Details of device type specific updates available
28 | */
29 | public let devicetypes: SoftwareUpdateStatusDeviceTypes?
30 |
31 | /**
32 | Release Notes Url
33 | */
34 | public let url: String?
35 |
36 | /**
37 | Update Text
38 | */
39 | public let text: String?
40 |
41 | /**
42 | Flag that turns to true when update is available. Can only be updated when its state is true and it is being set to false. All other transitions are invalid and will return an error.
43 | Updating this flag constitutes acceptance by the app of notification of the firmware update
44 | */
45 | public let notify: Bool?
46 |
47 | public init?(json: JSON) {
48 |
49 | updatestate = "updatestate" <~~ json
50 | checkforupdate = "checkforupdate" <~~ json
51 | devicetypes = "devicetypes" <~~ json
52 | url = "url" <~~ json
53 | text = "text" <~~ json
54 | notify = "notify" <~~ json
55 |
56 | }
57 |
58 | public func toJSON() -> JSON? {
59 |
60 | let json = jsonify([
61 | "updatestate" ~~> updatestate,
62 | "checkforupdate" ~~> checkforupdate,
63 | "devicetypes" ~~> devicetypes,
64 | "url" ~~> url,
65 | "text" ~~> text,
66 | "notify" ~~> notify
67 | ])
68 |
69 | return json
70 | }
71 | }
72 |
73 | extension SoftwareUpdateStatus: Hashable {
74 |
75 | public func hash(into hasher: inout Hasher) {
76 |
77 | hasher.combine(1)
78 | }
79 | }
80 |
81 | public func ==(lhs: SoftwareUpdateStatus, rhs: SoftwareUpdateStatus) -> Bool {
82 | return lhs.updatestate == rhs.updatestate &&
83 | lhs.checkforupdate == rhs.checkforupdate &&
84 | lhs.devicetypes == rhs.devicetypes &&
85 | lhs.url == rhs.url &&
86 | lhs.text == rhs.text &&
87 | lhs.notify == rhs.notify
88 | }
89 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/SoftwareUpdateStatusDeviceTypes.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SoftwareUpdateStatusDeviceTypes.swift
3 | // Pods
4 | //
5 | // Created by Marcel Dittmann on 22.04.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public struct SoftwareUpdateStatusDeviceTypes: JSONDecodable {
13 |
14 | /**
15 | Flag for when bridge update is avaliable
16 | */
17 | public let bridge: Bool?
18 |
19 | /**
20 | List of IDs of lights to be updated.
21 | */
22 | public let lights: [String]?
23 |
24 | /**
25 | List of IDs of sensors to be updated
26 | */
27 | public let sensors: [String]?
28 |
29 | public init?(json: JSON) {
30 |
31 | bridge = "bridge" <~~ json
32 | lights = "lights" <~~ json
33 | sensors = "sensors" <~~ json
34 |
35 | }
36 |
37 | public func toJSON() -> JSON? {
38 |
39 | let json = jsonify([
40 | "bridge" ~~> bridge,
41 | "lights" ~~> lights,
42 | "sensors" ~~> sensors,
43 | ])
44 |
45 | return json
46 | }
47 | }
48 |
49 | extension SoftwareUpdateStatusDeviceTypes: Hashable {
50 |
51 | public func hash(into hasher: inout Hasher) {
52 |
53 | hasher.combine(1)
54 | }
55 | }
56 |
57 | public func ==(lhs: SoftwareUpdateStatusDeviceTypes, rhs: SoftwareUpdateStatusDeviceTypes) -> Bool {
58 | return (lhs.bridge ?? false) == (rhs.bridge ?? false) &&
59 | (lhs.lights ?? []) == (rhs.lights ?? []) &&
60 | (lhs.sensors ?? []) == (rhs.sensors ?? [])
61 | }
62 |
--------------------------------------------------------------------------------
/Sources/Base/BridgeResourceModels/WhitelistEntry.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WhitelistEntry.swift
3 | // Pods
4 | //
5 | // Created by Marcel Dittmann on 22.04.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Gloss
11 |
12 | public struct WhitelistEntry: BridgeResource, BridgeResourceDictGenerator {
13 |
14 | public typealias AssociatedBridgeResourceType = WhitelistEntry
15 |
16 | public var resourceType: BridgeResourceType {
17 | return .whitelistEntry
18 | };
19 |
20 | public let identifier: String
21 |
22 | /**
23 | The date when the entry is used for the last time
24 | */
25 | public let lastUseDate: Date?
26 |
27 | /**
28 | Creation date of the entry
29 | */
30 | public let createDate: Date?
31 |
32 | /**
33 | Name of the entry
34 | */
35 | public let name: String
36 |
37 | public var username: String? {
38 | return identifier;
39 | }
40 |
41 | public init?(json: JSON) {
42 |
43 | let dateFormatter = DateFormatter.hueApiDateFormatter
44 |
45 | guard let identifier: String = "id" <~~ json,
46 | let name: String = "name" <~~ json,
47 | let lastUseDate: Date = Decoder.decode(dateForKey: "last use date", dateFormatter:dateFormatter)(json),
48 | let createDate: Date = Decoder.decode(dateForKey: "create date", dateFormatter: dateFormatter)(json)
49 | else { return nil }
50 |
51 | self.identifier = identifier
52 | self.name = name
53 | self.lastUseDate = lastUseDate as Date
54 | self.createDate = createDate as Date
55 |
56 | }
57 |
58 | public func toJSON() -> JSON? {
59 |
60 | let dateFormatter = DateFormatter.hueApiDateFormatter
61 |
62 | let json = jsonify([
63 | "id" ~~> identifier,
64 | "name" ~~> name,
65 | Encoder.encode(dateForKey: "last use date", dateFormatter: dateFormatter)(lastUseDate),
66 | Encoder.encode(dateForKey: "create date", dateFormatter: dateFormatter)(createDate)
67 | ])
68 |
69 | return json
70 | }
71 | }
72 |
73 | extension WhitelistEntry: Hashable {
74 |
75 | public func hash(into hasher: inout Hasher) {
76 |
77 | hasher.combine(Int(self.identifier)!)
78 | }
79 | }
80 |
81 | public func ==(lhs: WhitelistEntry, rhs: WhitelistEntry) -> Bool {
82 | return lhs.identifier == rhs.identifier &&
83 | lhs.name == rhs.identifier &&
84 | lhs.lastUseDate == rhs.lastUseDate &&
85 | lhs.createDate == rhs.createDate
86 | }
87 |
--------------------------------------------------------------------------------
/Sources/Base/Dictionary+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Dictionary+Extension.swift
3 | // Pods
4 | //
5 | // Created by Jerome Schmitz on 16.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | extension Dictionary {
12 | mutating func unionInPlace(
13 | _ dictionary: Dictionary) {
14 | for (key, value) in dictionary {
15 | self[key] = value
16 | }
17 | }
18 |
19 | // Thanks Airspeed Velocity
20 | mutating func unionInPlace(_ sequence: S) where
21 | S.Iterator.Element == (Key,Value) {
22 | for (key, value) in sequence {
23 | self[key] = value
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Sources/Base/Logger/LoggerConfig.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LoggerConfig.swift
3 | // Pods
4 | //
5 | // Created by Marcel Dittmann on 15.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | //import Log
11 |
12 | /*let Log = Logger(formatter: .Detailed, theme: .TomorrowNight)
13 |
14 | extension Formatters {
15 | static let Detailed = Formatter("[%@] %@.%@:%@ %@: %@", [
16 | .date("yyyy-MM-dd HH:mm:ss.SSS"),
17 | .file(fullPath: false, fileExtension: false),
18 | .function,
19 | .line,
20 | .level,
21 | .message
22 | ])
23 | }
24 |
25 | extension Themes {
26 | static let TomorrowNight = Theme(
27 | trace: "#C5C8C6",
28 | debug: "#81A2BE",
29 | info: "#B5BD68",
30 | warning: "#F0C674",
31 | error: "#CC6666"
32 | )
33 | }*/
34 |
--------------------------------------------------------------------------------
/Sources/Base/NSDateFormatter+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSDateFormatter+Extension.swift
3 | // Pods
4 | //
5 | // Created by Marcel Dittmann on 22.04.16.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public extension DateFormatter {
12 |
13 | static public var hueApiDateFormatter: DateFormatter {
14 |
15 | let dateFormatter = DateFormatter()
16 | dateFormatter.locale = Locale(identifier: "en_US")
17 | dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
18 |
19 | return dateFormatter
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/Base/ReplaceMe.swift:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Spriter/SwiftyHue/5309c5b8473085b607469ff5a0c26b4bfea0867b/Sources/Base/ReplaceMe.swift
--------------------------------------------------------------------------------
/Sources/Base/ResourceAPI.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResourceAPI.swift
3 | // SwiftyHue
4 | //
5 | // Created by Marcel Dittmann on 02.11.17.
6 | //
7 |
8 | import Foundation
9 |
10 | import Foundation
11 | import Alamofire
12 | import Gloss
13 |
14 | public class ResourceAPI {
15 |
16 | private var bridgeAccessConfig: BridgeAccessConfig?;
17 |
18 | func setBridgeAccessConfig(_ bridgeAccessConfig: BridgeAccessConfig) {
19 |
20 | self.bridgeAccessConfig = bridgeAccessConfig
21 | }
22 |
23 | public func fetch(resource: HeartbeatBridgeResourceType, completionHandler:@escaping (Alamofire.Result<[String: Resource]>) -> ()) where Resource.AssociatedBridgeResourceType == Resource {
24 |
25 | guard let bridgeAccessConfig = bridgeAccessConfig else {
26 |
27 | completionHandler(Alamofire.Result.failure(HueError(address: "SwiftyHue", errorDescription: "No bridgeAccessConfig available", type: 1)!))
28 | return
29 | }
30 |
31 | let url = "http://\(bridgeAccessConfig.ipAddress)/api/\(bridgeAccessConfig.username)/\(resource.rawValue.lowercased())"
32 |
33 | Alamofire.request(url).responseJSON { response in
34 |
35 | switch response.result {
36 |
37 | case .success(let data) where data is JSON:
38 |
39 | let resources = Resource.dictionaryFromResourcesJSON(data as! JSON)
40 | completionHandler(.success(resources))
41 |
42 | case .success(_):
43 | completionHandler(.failure(NSError(domain: "unexpected response", code: 0, userInfo: nil)))
44 |
45 | case .failure(let error):
46 | completionHandler(.failure(error))
47 | }
48 | }
49 | }
50 |
51 | public func fetchLights(_ completionHandler: @escaping (Alamofire.Result<[String: Light]>) -> ()) {
52 | fetch(resource: .lights, completionHandler: completionHandler)
53 | }
54 |
55 | public func fetchGroups(_ completionHandler: @escaping (Alamofire.Result<[String: Group]>) -> ()) {
56 | fetch(resource: .groups, completionHandler: completionHandler)
57 | }
58 |
59 | public func fetchScenes(_ completionHandler: @escaping (Alamofire.Result<[String: PartialScene]>) -> ()) {
60 | fetch(resource: .scenes, completionHandler: completionHandler)
61 | }
62 |
63 | public func fetchRules(_ completionHandler: @escaping (Alamofire.Result<[String: Rule]>) -> ()) {
64 | fetch(resource: .rules, completionHandler: completionHandler)
65 | }
66 |
67 | public func fetchSensors(_ completionHandler: @escaping (Alamofire.Result<[String: Sensor]>) -> ()) {
68 | fetch(resource: .sensors, completionHandler: completionHandler)
69 | }
70 |
71 | public func fetchSchedules(_ completionHandler: @escaping (Alamofire.Result<[String: Schedule]>) -> ()) {
72 | fetch(resource: .schedules, completionHandler: completionHandler)
73 | }
74 | }
75 |
76 |
--------------------------------------------------------------------------------
/Sources/Base/SwiftyHue.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftyHue.swift
3 | // Pods
4 | //
5 | // Created by Marcel Dittmann on 15.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | //import Log
11 |
12 | public class SwiftyHue: NSObject {
13 |
14 | // MARK: Public Interface
15 | public var resourceCache: BridgeResourcesCache?;
16 |
17 | public var bridgeSendAPI: BridgeSendAPI = BridgeSendAPI()
18 |
19 | public var resourceAPI: ResourceAPI = ResourceAPI()
20 |
21 | public func setBridgeAccessConfig(_ bridgeAccessConfig: BridgeAccessConfig, resourceCacheHeartbeatProcessorDelegate: ResourceCacheHeartbeatProcessorDelegate? = nil) {
22 |
23 | self.bridgeAccessConfig = bridgeAccessConfig;
24 | self.resourceCacheHeartbeatProcessor = ResourceCacheHeartbeatProcessor(delegate: resourceCacheHeartbeatProcessorDelegate ?? self);
25 | self.bridgeSendAPI.setBridgeAccessConfig(bridgeAccessConfig)
26 | self.resourceAPI.setBridgeAccessConfig(bridgeAccessConfig)
27 | self.heartbeatManager = HeartbeatManager(bridgeAccesssConfig: bridgeAccessConfig, heartbeatProcessors: [resourceCacheHeartbeatProcessor!]);
28 | }
29 |
30 | public func setLocalHeartbeatInterval(_ interval: TimeInterval, forResourceType resourceType: HeartbeatBridgeResourceType) {
31 |
32 | heartbeatManager?.setLocalHeartbeatInterval(interval, forResourceType: resourceType)
33 | }
34 |
35 | public func removeLocalHeartbeat(forResourceType resourceType: HeartbeatBridgeResourceType) {
36 |
37 | heartbeatManager?.removeLocalHeartbeat(forResourceType: resourceType)
38 | }
39 |
40 | public func startHeartbeat() {
41 |
42 | heartbeatManager?.startHeartbeat()
43 | }
44 |
45 | public func stopHeartbeat() {
46 |
47 | heartbeatManager?.stopHeartbeat()
48 | }
49 |
50 | // MARK: Logging
51 |
52 | public func enableLogging(_ enabled: Bool) {
53 | //Log.enabled = enabled
54 | }
55 |
56 | /**
57 | The minimum level of severity for the Logger.
58 | */
59 | /*public func setMinLevelForLogMessages(_ level: Level) {
60 |
61 | //Log.minLevel = level
62 | }*/
63 |
64 | // MARK: Private
65 | private var bridgeAccessConfig: BridgeAccessConfig?;
66 | private var heartbeatManager: HeartbeatManager?;
67 | private var resourceCacheHeartbeatProcessor: ResourceCacheHeartbeatProcessor?;
68 |
69 | /*public override init() {
70 | super.init()
71 | //enableLogging(false)
72 | }*/
73 | }
74 |
75 | extension SwiftyHue: ResourceCacheHeartbeatProcessorDelegate {
76 |
77 | public func resourceCacheUpdated(_ resourceCache: BridgeResourcesCache) {
78 |
79 | self.resourceCache = resourceCache;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Sources/BridgeServices/BridgeAuthenticator/BridgeAuthenticatorDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BridgeAuthenticatorDelegate.swift
3 | // Pods
4 | //
5 | // Created by Nils Lattek on 05.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol BridgeAuthenticatorDelegate: class {
12 | func bridgeAuthenticator(_ authenticator: BridgeAuthenticator, didFinishAuthentication username: String)
13 | func bridgeAuthenticator(_ authenticator: BridgeAuthenticator, didFailWithError error: NSError)
14 | // you should now ask the user to press the link button
15 | func bridgeAuthenticatorRequiresLinkButtonPress(_ authenticator: BridgeAuthenticator, secondsLeft: TimeInterval)
16 | // user did not press the link button in time, you restart the process and try again
17 | func bridgeAuthenticatorDidTimeout(_ authenticator: BridgeAuthenticator)
18 | }
19 |
--------------------------------------------------------------------------------
/Sources/BridgeServices/BridgeFinder/BridgeFinder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BridgeFinder.swift
3 | // HueSDK
4 | //
5 | // Created by Nils Lattek on 24.04.16.
6 | // Copyright © 2016 Nils Lattek. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | //import Log
11 |
12 | /// Use this class to find HueBridges on the current network.
13 | public class BridgeFinder: NSObject, ScannerDelegate {
14 | private var foundBridges = [HueBridge]()
15 | private let allScannerClasses: [Scanner.Type]
16 | private var remainingScannerClasses: [Scanner.Type] = []
17 | private var currentScanner: Scanner?
18 | private let validator: BridgeValidator
19 | public weak var delegate: BridgeFinderDelegate?
20 |
21 | public override convenience init() {
22 | // The recommended search order from Philips is SSDPScanner, NUPNPScanner,
23 | // IPScanner (not implemented currently).
24 | self.init(validator: BridgeValidator(), scannerClasses: [SSDPScanner.self, NUPNPScanner.self])
25 | }
26 |
27 | init(validator: BridgeValidator, scannerClasses: [Scanner.Type]) {
28 | self.validator = validator
29 | // Given the recommened order from Phillips and in order to avoid
30 | // dealing with checking the length of this array using remove(at:0)
31 | // so we don't get an IndexError, we are going to use popLast() -> T?
32 | // to pull the items out of it. To do that and maintain the
33 | // recommened order from Phillips we need to reverse the array as we
34 | // declared it's contents in the recommended order.
35 | self.allScannerClasses = scannerClasses.reversed()
36 | super.init()
37 | }
38 |
39 | /// Start scanning, make sure to assign a delegate to get notified about the results.
40 | public func start() {
41 | remainingScannerClasses = allScannerClasses
42 | startNextScanner()
43 | }
44 |
45 | private func startNextScanner() {
46 | guard let scannerClass = remainingScannerClasses.popLast() else {
47 | // all scanners finished, no bridges found
48 | DispatchQueue.main.async {
49 | self.delegate?.bridgeFinder(self, didFinishWithResult: self.foundBridges)
50 | }
51 | return
52 | }
53 |
54 | //Log.trace("Scanner started: \(scannerClass)")
55 | currentScanner = scannerClass.init(delegate: self)
56 | currentScanner?.start()
57 | }
58 |
59 | private func validateBridges(_ ips: [String]) {
60 | // create mutable copy, use recursion to check if every bridge has been validated
61 | var ips = ips
62 |
63 | guard let ip = ips.popLast() else {
64 | // all ips validated for current scanner
65 | ipValidationFinished()
66 | return
67 | }
68 |
69 | validator.validate(ip, success: { [weak self] (bridge) in
70 | if let this = self {
71 | this.foundBridges.append(bridge)
72 | this.validateBridges(ips)
73 | }
74 | }, failure: { [weak self] (error) in
75 | if let this = self {
76 | this.validateBridges(ips)
77 | }
78 | })
79 | }
80 |
81 | private func ipValidationFinished() {
82 | if foundBridges.count == 0 {
83 | // no bridges found, continue with next scanner
84 | startNextScanner()
85 | } else {
86 | DispatchQueue.main.async {
87 | self.delegate?.bridgeFinder(self, didFinishWithResult: self.foundBridges)
88 | }
89 | }
90 | }
91 |
92 | // MARK: - ScannerDelegate
93 |
94 | func scanner(_ scanner: Scanner, didFinishWithResults ips: [String]) {
95 | //Log.trace("Scanner finished: \(scanner) with result count: \(ips.count)")
96 | validateBridges(ips)
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Sources/BridgeServices/BridgeFinder/BridgeFinderDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BridgeFinderDelegate.swift
3 | // HueSDK
4 | //
5 | // Created by Nils Lattek on 24.04.16.
6 | // Copyright © 2016 Nils Lattek. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /// Protocol for handling BridgeFinder results
12 | public protocol BridgeFinderDelegate: class {
13 | /**
14 | Search for HueBridges finished.
15 |
16 | - Parameters:
17 | - finder: The BridgeFinder
18 | - bridges: An array containing all found bridges. If none was found the array will be empty.
19 | */
20 | func bridgeFinder(_ finder: BridgeFinder, didFinishWithResult bridges: [HueBridge])
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/BridgeServices/BridgeFinder/HueBridge.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HueBridge.swift
3 | // HueSDK
4 | //
5 | // Created by Nils Lattek on 24.04.16.
6 | // Copyright © 2016 Nils Lattek. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public struct HueBridge {
12 | public let ip: String
13 | public let deviceType: String
14 | public let friendlyName: String
15 | public let modelDescription: String
16 | public let modelName: String
17 | public let serialNumber: String
18 | public let UDN: String
19 | public let icons: [HueBridgeIcon]
20 |
21 | public init(ip: String, deviceType: String, friendlyName: String, modelDescription: String, modelName: String, serialNumber: String, UDN: String, icons: [HueBridgeIcon]) {
22 | self.ip = ip
23 | self.deviceType = deviceType
24 | self.friendlyName = friendlyName
25 | self.modelDescription = modelDescription
26 | self.modelName = modelName
27 | self.serialNumber = serialNumber
28 | self.UDN = UDN
29 | self.icons = icons
30 | }
31 | }
--------------------------------------------------------------------------------
/Sources/BridgeServices/BridgeFinder/HueBridgeIcon.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HueBridgeIcon.swift
3 | // HueSDK
4 | //
5 | // Created by Nils Lattek on 24.04.16.
6 | // Copyright © 2016 Nils Lattek. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public struct HueBridgeIcon {
12 | public let mimetype: String
13 | public let height: Int
14 | public let width: Int
15 | public let name: String
16 | }
--------------------------------------------------------------------------------
/Sources/BridgeServices/BridgeFinder/Scanner/IPScanner.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IPScanner.swift
3 | // HueSDK
4 | //
5 | // Created by Nils Lattek on 24.04.16.
6 | // Copyright © 2016 Nils Lattek. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
--------------------------------------------------------------------------------
/Sources/BridgeServices/BridgeFinder/Scanner/NUPNPScanner.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NUPNPScanner.swift
3 | // HueSDK
4 | //
5 | // Created by Nils Lattek on 24.04.16.
6 | // Copyright © 2016 Nils Lattek. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class NUPNPScanner: NSObject, Scanner {
12 | weak var delegate: ScannerDelegate?
13 |
14 | required init(delegate: ScannerDelegate? = nil) {
15 | self.delegate = delegate
16 | super.init()
17 | }
18 |
19 | func start() {
20 | let request = createRequest()
21 | startRequest(request as URLRequest)
22 | }
23 |
24 | func stop() {
25 |
26 | }
27 |
28 | private func createRequest() -> URLRequest {
29 | let url = URL(string: "https://www.meethue.com/api/nupnp")!
30 |
31 | var request = URLRequest(url: url)
32 | request.httpMethod = "GET"
33 |
34 | return request
35 | }
36 |
37 | private func startRequest(_ request: URLRequest) {
38 | let task = URLSession.shared.dataTask(with: request) { [weak self] (data, response, error) in
39 | guard let this = self else {
40 | return
41 | }
42 |
43 | if error != nil || data == nil {
44 | this.delegate?.scanner(this, didFinishWithResults: [])
45 | return
46 | }
47 |
48 | let ips = this.parseResults(data!)
49 | this.delegate?.scanner(this, didFinishWithResults: ips)
50 | }
51 |
52 | task.resume()
53 | }
54 |
55 | private func parseResults(_ data: Data) -> [String] {
56 | var ips = [String]()
57 |
58 | do {
59 | if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: String]] {
60 | for bridgeJson in json {
61 | if let ip = bridgeJson["internalipaddress"] {
62 | ips.append(ip)
63 | }
64 | }
65 | }
66 |
67 |
68 | } catch let error as NSError {
69 | print("Error while parsing nupnp results: \(error)")
70 | }
71 |
72 | return ips
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/Sources/BridgeServices/BridgeFinder/Scanner/SSDPScanner.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SSDPScanner.swift
3 | // HueSDK
4 | //
5 | // Created by Nils Lattek on 24.04.16.
6 | // Copyright © 2016 Nils Lattek. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import CocoaAsyncSocket
11 |
12 | class SSDPScanner: NSObject, Scanner, GCDAsyncUdpSocketDelegate {
13 | private let ssdpSocket: GCDAsyncUdpSocket
14 | private let delegateQueue = DispatchQueue(label: "com.blowfishlab.SwiftyHue.ssdpscanner")
15 | private var results = Set()
16 | weak var delegate: ScannerDelegate?
17 |
18 | required init(delegate: ScannerDelegate? = nil) {
19 | self.delegate = delegate
20 | ssdpSocket = GCDAsyncUdpSocket()
21 | super.init()
22 | ssdpSocket.setDelegate(self, delegateQueue: delegateQueue)
23 | }
24 |
25 | func start() {
26 | do {
27 | try ssdpSocket.enableBroadcast(true)
28 | let searchData = "M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMan: \"ssdp:discover\"\r\nST: ssdp:all\r\n\r\n".data(using: .utf8)!
29 | let host = "239.255.255.250"
30 | let port: UInt16 = 1900
31 | // listen 102 error: https://github.com/robbiehanson/CocoaAsyncSocket/issues/376
32 | try ssdpSocket.bind(toPort: 0)
33 |
34 | ssdpSocket.send(searchData, toHost: host, port: port, withTimeout: 5, tag: 1)
35 | try ssdpSocket.beginReceiving()
36 |
37 | let receiveTimeout: TimeInterval = 5
38 | Timer.scheduledTimer(timeInterval: receiveTimeout, target: self, selector: #selector(SSDPScanner.stop), userInfo: self, repeats: false)
39 |
40 | } catch let error as NSError {
41 | print("Exception: \(error)")
42 | }
43 | }
44 |
45 | @objc func stop() {
46 | ssdpSocket.close()
47 | let ips = Array(results)
48 | delegate?.scanner(self, didFinishWithResults: ips)
49 | }
50 |
51 | // MARK: - GCDAsyncUdpSocketDelegate
52 |
53 | func udpSocket(_ sock: GCDAsyncUdpSocket, didReceive data: Data, fromAddress address: Data, withFilterContext: Any?){
54 | guard let result = String(data: data, encoding:.ascii) else {
55 | print("Could not decode ssdp data")
56 | return
57 | }
58 |
59 | if result.contains("IpBridge") {
60 | var host: NSString?
61 | var port: UInt16 = 0
62 |
63 | GCDAsyncUdpSocket.getHost(&host, port: &port, fromAddress: address)
64 | if let host = host as String? {
65 | results.insert(host)
66 | }
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/Sources/BridgeServices/BridgeFinder/Scanner/Scanner.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Scanner.swift
3 | // HueSDK
4 | //
5 | // Created by Nils Lattek on 24.04.16.
6 | // Copyright © 2016 Nils Lattek. All rights reserved.
7 | //
8 |
9 |
10 | protocol Scanner {
11 | var delegate: ScannerDelegate? { get set }
12 |
13 | init(delegate: ScannerDelegate?)
14 | func start()
15 | func stop()
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/BridgeServices/BridgeFinder/Scanner/ScannerDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScannerDelegate.swift
3 | // HueSDK
4 | //
5 | // Created by Nils Lattek on 24.04.16.
6 | // Copyright © 2016 Nils Lattek. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol ScannerDelegate: class {
12 | func scanner(_ scanner: Scanner, didFinishWithResults ips: [String])
13 | }
14 |
--------------------------------------------------------------------------------
/Sources/BridgeServices/BridgeFinder/Validator/BridgeResultParser.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BridgeResultParser.swift
3 | // HueSDK
4 | //
5 | // Created by Nils Lattek on 24.04.16.
6 | // Copyright © 2016 Nils Lattek. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class BridgeResultParser: NSObject, XMLParserDelegate {
12 | private let parser: XMLParser
13 | private var element: String = ""
14 | private var bridge: HueBridge?
15 | private var successBlock: ((_ bridge: HueBridge) -> Void)?
16 | private var failureBlock: ((_ error: NSError) -> Void)?
17 |
18 | private var urlBase: String = ""
19 | private var ip: String = ""
20 | private var deviceType: String = ""
21 | private var friendlyName: String = ""
22 | private var modelDescription: String = ""
23 | private var modelName: String = ""
24 | private var serialNumber: String = ""
25 | private var UDN: String = ""
26 | private var icons = [HueBridgeIcon]()
27 | private var mimetype: String = ""
28 | private var height: String = ""
29 | private var width: String = ""
30 | private var iconName: String = ""
31 |
32 | init(xmlData: Data) {
33 | parser = XMLParser(data: xmlData)
34 | super.init()
35 | parser.delegate = self
36 | }
37 |
38 | func parse(_ success: @escaping (_ bridge: HueBridge) -> Void, failure: @escaping (_ error: NSError) -> Void) {
39 | self.successBlock = success
40 | self.failureBlock = failure
41 |
42 | parser.parse()
43 | }
44 |
45 | private func cancelWithError(_ errorMessage: String) {
46 | parser.abortParsing()
47 | if let failureBlock = failureBlock {
48 | failureBlock(NSError(domain: "HueBridgeParser", code: 500, userInfo: [NSLocalizedDescriptionKey: errorMessage]))
49 | }
50 | }
51 |
52 | // MARK: - NSXMLParserDelegate
53 |
54 | public func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
55 | element = elementName
56 |
57 | if elementName == "root" {
58 | if attributeDict["xmlns"] == nil || attributeDict["xmlns"] != "urn:schemas-upnp-org:device-1-0" {
59 | cancelWithError("XML is not a known HueBridge XML.")
60 | }
61 | } else if elementName == "icon" {
62 | mimetype = ""
63 | height = ""
64 | width = ""
65 | iconName = ""
66 | }
67 | }
68 |
69 | public func parser(_ parser: XMLParser, foundCharacters string: String) {
70 | switch element {
71 | case "deviceType":
72 | deviceType += string
73 | case "friendlyName":
74 | friendlyName += string
75 | case "modelDescription":
76 | modelDescription += string
77 | case "modelName":
78 | modelName += string
79 | case "serialNumber":
80 | serialNumber += string
81 | case "UDN":
82 | UDN += string
83 | case "URLBase":
84 | urlBase += string
85 | case "mimetype":
86 | mimetype += string
87 | case "height":
88 | height += string
89 | case "width":
90 | width += string
91 | case "url":
92 | iconName += string
93 | default: break
94 | }
95 | }
96 |
97 | public func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
98 | element = ""
99 |
100 | if elementName == "device" {
101 | if isBridgeDataValid() {
102 | bridge = HueBridge(ip: ip, deviceType: deviceType, friendlyName: friendlyName, modelDescription: modelDescription, modelName: modelName, serialNumber: serialNumber, UDN: UDN, icons: icons)
103 | } else {
104 | cancelWithError("HueBridge data not valid.")
105 | }
106 | } else if elementName == "URLBase" {
107 | let url = URL(string: urlBase)
108 | if let host = url?.host {
109 | ip = host
110 | }
111 | } else if elementName == "icon" {
112 | if let height = Int(height), let width = Int(width) {
113 | icons.append(HueBridgeIcon(mimetype: mimetype, height: height, width: width, name: iconName))
114 | }
115 | }
116 | }
117 |
118 | public func parserDidEndDocument(_ parser: XMLParser) {
119 | if let successBlock = successBlock, let bridge = bridge {
120 | successBlock(bridge)
121 | }
122 | }
123 |
124 | private func isBridgeDataValid() -> Bool {
125 | return ip.count != 0 && deviceType.count != 0
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/Sources/BridgeServices/BridgeFinder/Validator/BridgeValidator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VerifyBridge.swift
3 | // HueSDK
4 | //
5 | // Given an IP-Adress it tries to retrieve more information about the HUE Bridge.
6 | //
7 | // Created by Nils Lattek on 24.04.16.
8 | // Copyright © 2016 Nils Lattek. All rights reserved.
9 | //
10 |
11 | import Foundation
12 |
13 | class BridgeValidator {
14 | func validate(_ ip: String, success: @escaping (_ bridge: HueBridge) -> Void, failure: @escaping (_ error: NSError) -> Void) {
15 | let request = createRequest(ip)
16 | startRequest(request as URLRequest, success: success, failure: failure)
17 | }
18 |
19 | private func createRequest(_ ip: String) -> NSMutableURLRequest {
20 | let url = URL(string: "http://\(ip)/description.xml")!
21 |
22 | let request = NSMutableURLRequest(url: url)
23 | request.httpMethod = "GET"
24 |
25 | return request
26 | }
27 |
28 | private func startRequest(_ request: URLRequest, success: @escaping (_ bridge: HueBridge) -> Void, failure: @escaping (_ error: NSError) -> Void) {
29 | let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
30 | if let error = error {
31 | failure(error as NSError)
32 | return
33 | }
34 |
35 | guard let data = data else {
36 | failure(NSError(domain: "HueBridgeValidator", code: 500, userInfo: [NSLocalizedDescriptionKey: "No data from bridge received."]))
37 | return
38 | }
39 |
40 | // TODO: check specVersion/xmlns and use correct parser
41 | let parser = BridgeResultParser(xmlData: data)
42 | parser.parse(success, failure: failure)
43 | }
44 |
45 | task.resume()
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Sources/Info-iOS.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Sources/Info-tvOS.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Sources/Info-watchOS.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Sources/SwiftyHue.h:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftyHue iOS.h
3 | // SwiftyHue iOS
4 | //
5 | // Created by Marcel Dittmann on 25.05.16.
6 | //
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for SwiftyHue iOS.
12 | FOUNDATION_EXPORT double SwiftyHueVersionNumber;
13 |
14 | //! Project version string for SwiftyHue iOS.
15 | FOUNDATION_EXPORT const unsigned char SwiftyHueVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
--------------------------------------------------------------------------------
/SwiftyHue Example Watch Extension/Assets.xcassets/README__ignoredByTemplate__:
--------------------------------------------------------------------------------
1 | Did you know that git does not support storing empty directories?
2 |
--------------------------------------------------------------------------------
/SwiftyHue Example Watch Extension/ExtensionDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExtensionDelegate.swift
3 | // SwiftyHue Example Watch Extension
4 | //
5 | // Created by Marcel Dittmann on 25.05.16.
6 | //
7 | //
8 |
9 | import WatchKit
10 |
11 | class ExtensionDelegate: NSObject, WKExtensionDelegate {
12 |
13 | func applicationDidFinishLaunching() {
14 | // Perform any final initialization of your application.
15 | }
16 |
17 | func applicationDidBecomeActive() {
18 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
19 | }
20 |
21 | func applicationWillResignActive() {
22 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
23 | // Use this method to pause ongoing tasks, disable timers, etc.
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/SwiftyHue Example Watch Extension/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | SwiftyHue Example Watch Extension
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | XPC!
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | NSExtension
26 |
27 | NSExtensionAttributes
28 |
29 | WKAppBundleIdentifier
30 | com.blowfishlab.SwiftyHue-Example.watchkitapp
31 |
32 | NSExtensionPointIdentifier
33 | com.apple.watchkit
34 |
35 | WKExtensionDelegateClassName
36 | $(PRODUCT_MODULE_NAME).ExtensionDelegate
37 |
38 |
39 |
--------------------------------------------------------------------------------
/SwiftyHue Example Watch Extension/InterfaceController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // InterfaceController.swift
3 | // SwiftyHue Example Watch Extension
4 | //
5 | // Created by Marcel Dittmann on 25.05.16.
6 | //
7 | //
8 |
9 | import WatchKit
10 | import Foundation
11 |
12 |
13 | class InterfaceController: WKInterfaceController {
14 |
15 | // override func awakeWithContext(context: AnyObject?) {
16 | // super.awake(withContext: context)
17 | //
18 | // // Configure interface objects here.
19 | // }
20 |
21 | override func willActivate() {
22 | // This method is called when watch view controller is about to be visible to user
23 | super.willActivate()
24 | }
25 |
26 | override func didDeactivate() {
27 | // This method is called when watch view controller is no longer visible
28 | super.didDeactivate()
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/SwiftyHue Example Watch/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "24x24",
5 | "idiom" : "watch",
6 | "scale" : "2x",
7 | "role" : "notificationCenter",
8 | "subtype" : "38mm"
9 | },
10 | {
11 | "size" : "27.5x27.5",
12 | "idiom" : "watch",
13 | "scale" : "2x",
14 | "role" : "notificationCenter",
15 | "subtype" : "42mm"
16 | },
17 | {
18 | "size" : "29x29",
19 | "idiom" : "watch",
20 | "role" : "companionSettings",
21 | "scale" : "2x"
22 | },
23 | {
24 | "size" : "29x29",
25 | "idiom" : "watch",
26 | "role" : "companionSettings",
27 | "scale" : "3x"
28 | },
29 | {
30 | "size" : "40x40",
31 | "idiom" : "watch",
32 | "scale" : "2x",
33 | "role" : "appLauncher",
34 | "subtype" : "38mm"
35 | },
36 | {
37 | "size" : "86x86",
38 | "idiom" : "watch",
39 | "scale" : "2x",
40 | "role" : "quickLook",
41 | "subtype" : "38mm"
42 | },
43 | {
44 | "size" : "98x98",
45 | "idiom" : "watch",
46 | "scale" : "2x",
47 | "role" : "quickLook",
48 | "subtype" : "42mm"
49 | }
50 | ],
51 | "info" : {
52 | "version" : 1,
53 | "author" : "xcode"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/SwiftyHue Example Watch/Base.lproj/Interface.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/SwiftyHue Example Watch/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | SwiftyHue Example
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | UISupportedInterfaceOrientations
26 |
27 | UIInterfaceOrientationPortrait
28 | UIInterfaceOrientationPortraitUpsideDown
29 |
30 | WKCompanionAppBundleIdentifier
31 | com.blowfishlab.SwiftyHue-Example
32 | WKWatchKitApp
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // SwiftyHue Example tvOS
4 | //
5 | // Created by Marcel Dittmann on 25.05.16.
6 | //
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "layers" : [
3 | {
4 | "filename" : "Front.imagestacklayer"
5 | },
6 | {
7 | "filename" : "Middle.imagestacklayer"
8 | },
9 | {
10 | "filename" : "Back.imagestacklayer"
11 | }
12 | ],
13 | "info" : {
14 | "version" : 1,
15 | "author" : "xcode"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "layers" : [
3 | {
4 | "filename" : "Front.imagestacklayer"
5 | },
6 | {
7 | "filename" : "Middle.imagestacklayer"
8 | },
9 | {
10 | "filename" : "Back.imagestacklayer"
11 | }
12 | ],
13 | "info" : {
14 | "version" : 1,
15 | "author" : "xcode"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "assets" : [
3 | {
4 | "size" : "1280x768",
5 | "idiom" : "tv",
6 | "filename" : "App Icon - Large.imagestack",
7 | "role" : "primary-app-icon"
8 | },
9 | {
10 | "size" : "400x240",
11 | "idiom" : "tv",
12 | "filename" : "App Icon - Small.imagestack",
13 | "role" : "primary-app-icon"
14 | },
15 | {
16 | "size" : "1920x720",
17 | "idiom" : "tv",
18 | "filename" : "Top Shelf Image.imageset",
19 | "role" : "top-shelf-image"
20 | }
21 | ],
22 | "info" : {
23 | "version" : 1,
24 | "author" : "xcode"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "landscape",
5 | "idiom" : "tv",
6 | "extent" : "full-screen",
7 | "minimum-system-version" : "9.0",
8 | "scale" : "1x"
9 | }
10 | ],
11 | "info" : {
12 | "version" : 1,
13 | "author" : "xcode"
14 | }
15 | }
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/Assets.xcassets/first.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "first.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/Assets.xcassets/first.imageset/first.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Spriter/SwiftyHue/5309c5b8473085b607469ff5a0c26b4bfea0867b/SwiftyHue Example tvOS/Assets.xcassets/first.imageset/first.pdf
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/Assets.xcassets/second.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "second.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/Assets.xcassets/second.imageset/second.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Spriter/SwiftyHue/5309c5b8473085b607469ff5a0c26b4bfea0867b/SwiftyHue Example tvOS/Assets.xcassets/second.imageset/second.pdf
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/FirstViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FirstViewController.swift
3 | // SwiftyHue Example tvOS
4 | //
5 | // Created by Marcel Dittmann on 25.05.16.
6 | //
7 | //
8 |
9 | import UIKit
10 |
11 | class FirstViewController: UIViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 | // Do any additional setup after loading the view, typically from a nib.
16 | }
17 |
18 | override func didReceiveMemoryWarning() {
19 | super.didReceiveMemoryWarning()
20 | // Dispose of any resources that can be recreated.
21 | }
22 |
23 |
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | arm64
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/SwiftyHue Example tvOS/SecondViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SecondViewController.swift
3 | // SwiftyHue Example tvOS
4 | //
5 | // Created by Marcel Dittmann on 25.05.16.
6 | //
7 | //
8 |
9 | import UIKit
10 |
11 | class SecondViewController: UIViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 | // Do any additional setup after loading the view, typically from a nib.
16 | }
17 |
18 | override func didReceiveMemoryWarning() {
19 | super.didReceiveMemoryWarning()
20 | // Dispose of any resources that can be recreated.
21 | }
22 |
23 |
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/SwiftyHue Example/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // SwiftyHue
4 | //
5 | // Created by Marcel Dittmann on 04/21/2016.
6 | // Copyright (c) 2016 Marcel Dittmann. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 |
20 | return true
21 | }
22 |
23 | func applicationWillResignActive(_ application: UIApplication) {
24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
26 | }
27 |
28 | func applicationDidEnterBackground(_ application: UIApplication) {
29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
31 | }
32 |
33 | func applicationWillEnterForeground(_ application: UIApplication) {
34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
35 | }
36 |
37 | func applicationDidBecomeActive(_ application: UIApplication) {
38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
39 | }
40 |
41 | func applicationWillTerminate(_ application: UIApplication) {
42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
43 | }
44 |
45 |
46 | }
47 |
48 |
--------------------------------------------------------------------------------
/SwiftyHue Example/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
20 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/SwiftyHue Example/BridgeAccessConfigPresentationViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BridgeAccessConfigPresentationViewController.swift
3 | // SwiftyHue
4 | //
5 | // Created by Marcel Dittmann on 08.05.16.
6 | // Copyright © 2016 CocoaPods. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SwiftyHue
11 |
12 | class BridgeAccessConfigPresentationViewController: UIViewController {
13 |
14 | var bridgeAccesssConfig: BridgeAccessConfig!
15 |
16 | @IBOutlet var usernameLabel: UILabel!
17 | @IBOutlet var bridgeIdLabel: UILabel!
18 | @IBOutlet var ipLabel: UILabel!
19 |
20 | override func viewDidLoad() {
21 | super.viewDidLoad()
22 |
23 | // Do any additional setup after loading the view.
24 | }
25 |
26 | override func viewDidAppear(_ animated: Bool) {
27 | super.viewDidAppear(animated)
28 |
29 | usernameLabel?.text = bridgeAccesssConfig.username
30 | bridgeIdLabel?.text = bridgeAccesssConfig.bridgeId
31 | ipLabel?.text = bridgeAccesssConfig.ipAddress
32 | }
33 |
34 | override func didReceiveMemoryWarning() {
35 | super.didReceiveMemoryWarning()
36 | // Dispose of any resources that can be recreated.
37 | }
38 |
39 | @IBAction func okButtonTapped(_ sender: AnyObject) {
40 |
41 | (navigationController as! CreateBridgeAccessController).bridgeAccessCreated(bridgeAccessConfig: bridgeAccesssConfig)
42 | }
43 |
44 | /*
45 | // MARK: - Navigation
46 |
47 | // In a storyboard-based application, you will often want to do a little preparation before navigation
48 | override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
49 | // Get the new view controller using segue.destinationViewController.
50 | // Pass the selected object to the new view controller.
51 | }
52 | */
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/SwiftyHue Example/BridgePushLinkViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BridgePushLinkViewController.swift
3 | // SwiftyHue
4 | //
5 | // Created by Marcel Dittmann on 08.05.16.
6 | // Copyright © 2016 CocoaPods. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SwiftyHue
11 |
12 | class BridgePushLinkViewController: UIViewController {
13 |
14 | var bridge: HueBridge!;
15 | var bridgeAuthenticator: BridgeAuthenticator!
16 | var bridgeAccessConfig: BridgeAccessConfig!
17 |
18 | override func viewDidLoad() {
19 | super.viewDidLoad()
20 |
21 | // Do any additional setup after loading the view.
22 | }
23 |
24 | override func didReceiveMemoryWarning() {
25 | super.didReceiveMemoryWarning()
26 | // Dispose of any resources that can be recreated.
27 | }
28 |
29 | override func viewDidAppear(_ animated: Bool) {
30 | super.viewDidAppear(animated)
31 |
32 | bridgeAuthenticator = BridgeAuthenticator(bridge: bridge, uniqueIdentifier: "swiftyhue#\(UIDevice.current.name)")
33 | bridgeAuthenticator.delegate = self;
34 | bridgeAuthenticator.start()
35 | }
36 |
37 |
38 | /*
39 | // MARK: - Navigation
40 |
41 | // In a storyboard-based application, you will often want to do a little preparation before navigation
42 | override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
43 | // Get the new view controller using segue.destinationViewController.
44 | // Pass the selected object to the new view controller.
45 | }
46 | */
47 |
48 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
49 | let destController = segue.destination as! BridgeAccessConfigPresentationViewController;
50 | destController.bridgeAccesssConfig = bridgeAccessConfig;
51 | }
52 |
53 | }
54 |
55 | extension BridgePushLinkViewController: BridgeAuthenticatorDelegate {
56 |
57 | // you should now ask the user to press the link button
58 | func bridgeAuthenticatorRequiresLinkButtonPress(_ authenticator: BridgeAuthenticator, secondsLeft: TimeInterval) {
59 |
60 | }
61 |
62 |
63 | func bridgeAuthenticator(_ authenticator: BridgeAuthenticator, didFinishAuthentication username: String) {
64 |
65 | self.bridgeAccessConfig = BridgeAccessConfig(bridgeId: "BridgeId", ipAddress: bridge.ip, username: username)
66 |
67 | self.performSegue(withIdentifier: "BridgeAccessConfigPresentationViewControllerSegue", sender: self)
68 | }
69 |
70 | func bridgeAuthenticator(_ authenticator: BridgeAuthenticator, didFailWithError error: NSError) {
71 |
72 | print(error)
73 | }
74 |
75 |
76 |
77 | // user did not press the link button in time, you restart the process and try again
78 | func bridgeAuthenticatorDidTimeout(_ authenticator: BridgeAuthenticator) {
79 |
80 | print("timeout")
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/SwiftyHue Example/BridgeResourceTableViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BridgeResourceTableViewController.swift
3 | // SwiftyHue
4 | //
5 | // Created by Marcel Dittmann on 09.05.16.
6 | // Copyright © 2016 CocoaPods. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SwiftyHue
11 |
12 | class BridgeResourceTableViewController: UITableViewController {
13 |
14 | var resourceTypeToDisplay: HeartbeatBridgeResourceType = .lights
15 | var bridgeResources = [BridgeResource]()
16 |
17 | override func viewDidLoad() {
18 | super.viewDidLoad()
19 |
20 | updateResources()
21 | }
22 |
23 | func updateResources() {
24 |
25 | if let resourceCache = swiftyHue.resourceCache {
26 |
27 | switch resourceTypeToDisplay {
28 |
29 | case .lights:
30 |
31 | for light in resourceCache.lights.values {
32 | bridgeResources.append(light)
33 | }
34 |
35 | case .groups:
36 |
37 | for group in resourceCache.groups.values {
38 | bridgeResources.append(group)
39 | }
40 |
41 | case .scenes:
42 |
43 | for scene in resourceCache.scenes.values {
44 | bridgeResources.append(scene)
45 | }
46 |
47 | case .rules:
48 |
49 | for rule in resourceCache.rules.values {
50 | bridgeResources.append(rule)
51 | }
52 |
53 | case .schedules:
54 |
55 | for schedule in resourceCache.schedules.values {
56 | bridgeResources.append(schedule)
57 | }
58 |
59 | case .sensors:
60 |
61 | for sensor in resourceCache.sensors.values {
62 | bridgeResources.append(sensor)
63 | }
64 |
65 | case .config:
66 |
67 | if let config = resourceCache.bridgeConfiguration {
68 | bridgeResources.append(config)
69 | }
70 |
71 | }
72 | }
73 | }
74 |
75 | required init?(coder aDecoder: NSCoder) {
76 | super.init(coder: aDecoder)
77 | }
78 |
79 | override func didReceiveMemoryWarning() {
80 | super.didReceiveMemoryWarning()
81 | // Dispose of any resources that can be recreated.
82 | }
83 |
84 | // MARK: - Table view data source
85 |
86 | override func numberOfSections(in tableView: UITableView) -> Int {
87 |
88 | // #warning Incomplete implementation, return the number of sections
89 | return 1
90 | }
91 |
92 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
93 | return bridgeResources.count
94 | }
95 |
96 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
97 |
98 | let cell = tableView.dequeueReusableCell(withIdentifier: "BridgeResourceTableViewCell", for: indexPath)
99 |
100 | let bridgeResource = self.bridgeResources[indexPath.row]
101 |
102 | cell.textLabel?.text = bridgeResource.name
103 |
104 | return cell
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/SwiftyHue Example/BridgeSelectionTableViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BridgeSelectionTableViewController.swift
3 | // SwiftyHue
4 | //
5 | // Created by Marcel Dittmann on 08.05.16.
6 | // Copyright © 2016 CocoaPods. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SwiftyHue
11 |
12 | class BridgeSelectionTableViewController: UITableViewController {
13 |
14 | var bridgeFinder = BridgeFinder()
15 | var bridges: [HueBridge]?;
16 | var selectedBridge: HueBridge?
17 |
18 | override func viewDidLoad() {
19 |
20 | self.setBackgroundMessage(message: "Searching Bridge")
21 |
22 | }
23 |
24 | override func viewDidAppear(_ animated: Bool) {
25 | super.viewDidAppear(animated)
26 |
27 | bridgeFinder.delegate = self;
28 | bridgeFinder.start()
29 | }
30 |
31 | override func numberOfSections(in tableView: UITableView) -> Int {
32 |
33 | return 1
34 | }
35 |
36 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
37 |
38 | return bridges?.count ?? 0
39 | }
40 |
41 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
42 |
43 | let bridge = self.bridges![indexPath.row]
44 |
45 | let cell = tableView.dequeueReusableCell(withIdentifier: "BridgeCell", for: indexPath)
46 | cell.textLabel?.text = bridge.friendlyName
47 |
48 | return cell
49 | }
50 |
51 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
52 |
53 | selectedBridge = bridges![indexPath.row]
54 |
55 | performSegue(withIdentifier: "BridgePushLinkViewControllerSegue", sender: self)
56 | }
57 |
58 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
59 |
60 | let destController = segue.destination as! BridgePushLinkViewController;
61 | destController.bridge = selectedBridge
62 | }
63 | }
64 |
65 | extension BridgeSelectionTableViewController: BridgeFinderDelegate {
66 |
67 | func bridgeFinder(_ finder: BridgeFinder, didFinishWithResult bridges: [HueBridge]) {
68 |
69 | self.bridges = bridges;
70 | self.setBackgroundMessage(message: nil)
71 | self.tableView.reloadData()
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/SwiftyHue Example/CreateBridgeAccessController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CreateBridgeAccessController.swift
3 | // SwiftyHue
4 | //
5 | // Created by Marcel Dittmann on 08.05.16.
6 | // Copyright © 2016 CocoaPods. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SwiftyHue
11 |
12 | public protocol CreateBridgeAccessControllerDelegate: class {
13 |
14 | func bridgeAccessCreated(bridgeAccessConfig: BridgeAccessConfig)
15 | }
16 |
17 | public class CreateBridgeAccessController: UINavigationController {
18 |
19 | public weak var bridgeAccessCreationDelegate: CreateBridgeAccessControllerDelegate?
20 |
21 | func bridgeAccessCreated(bridgeAccessConfig: BridgeAccessConfig) {
22 |
23 | dismiss(animated: true, completion: nil)
24 | bridgeAccessCreationDelegate?.bridgeAccessCreated(bridgeAccessConfig: bridgeAccessConfig)
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/SwiftyHue Example/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/SwiftyHue Example/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/SwiftyHue Example/Images.xcassets/PressSmartbridgeV2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "press_smartbridgeV2.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwiftyHue Example/Images.xcassets/PressSmartbridgeV2.imageset/press_smartbridgeV2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Spriter/SwiftyHue/5309c5b8473085b607469ff5a0c26b4bfea0867b/SwiftyHue Example/Images.xcassets/PressSmartbridgeV2.imageset/press_smartbridgeV2.pdf
--------------------------------------------------------------------------------
/SwiftyHue Example/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | NSAppTransportSecurity
26 |
27 | NSAllowsArbitraryLoads
28 |
29 |
30 | UILaunchStoryboardName
31 | LaunchScreen
32 | UIMainStoryboardFile
33 | Main
34 | UIRequiredDeviceCapabilities
35 |
36 | armv7
37 |
38 | UISupportedInterfaceOrientations
39 |
40 | UIInterfaceOrientationPortrait
41 | UIInterfaceOrientationLandscapeLeft
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/SwiftyHue Example/SwiftyHue Example-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Use this file to import your target's public headers that you would like to expose to Swift.
3 | //
4 |
5 |
--------------------------------------------------------------------------------
/SwiftyHue Example/UITableViewController+Extensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UITableViewController+Extensions.swift
3 | // SwiftyHue
4 | //
5 | // Created by Marcel Dittmann on 08.05.16.
6 | // Copyright © 2016 CocoaPods. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UITableViewController {
12 |
13 | func setBackgroundMessage(message: String?) {
14 | if let message = message {
15 | // Display a message when the table is empty
16 | let messageLabel = UILabel()
17 |
18 | messageLabel.text = message
19 | messageLabel.font = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.body)
20 | messageLabel.textColor = UIColor.lightGray
21 | messageLabel.textAlignment = .center
22 | messageLabel.sizeToFit()
23 |
24 | tableView.backgroundView = messageLabel
25 | tableView.separatorStyle = .none
26 | }
27 | else {
28 | tableView.backgroundView = nil
29 | tableView.separatorStyle = .singleLine
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/SwiftyHue iOSTests/BridgeAuthenticatorConsumer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BridgeAuthenticatorConsumer.swift
3 | // SwiftyHue
4 | //
5 | // Created by Nils Lattek on 28.05.16.
6 | //
7 | //
8 |
9 | import XCTest
10 | import SwiftyHue
11 |
12 | class BridgeAuthenticatorConsumer: BridgeAuthenticatorDelegate {
13 | var asyncExpectation: XCTestExpectation?
14 | var timeoutCalled = false
15 | var failedWithError: NSError?
16 | var finishWithUsername: String?
17 | var ignoreLinkButtonCall = false
18 | var requiresLinkButtonCallCount = 0
19 |
20 | func bridgeAuthenticatorDidTimeout(_ authenticator: BridgeAuthenticator) {
21 | guard let expectation = asyncExpectation else {
22 | XCTFail("Set expectation in test")
23 | return
24 | }
25 |
26 | timeoutCalled = true
27 | expectation.fulfill()
28 | }
29 |
30 | func bridgeAuthenticatorRequiresLinkButtonPress(_ authenticator: BridgeAuthenticator) {
31 | requiresLinkButtonCallCount += 1
32 | if ignoreLinkButtonCall {
33 | return
34 | }
35 |
36 | guard let expectation = asyncExpectation else {
37 | XCTFail("Set expectation in test")
38 | return
39 | }
40 |
41 | expectation.fulfill()
42 | }
43 |
44 | func bridgeAuthenticator(_ authenticator: BridgeAuthenticator, didFailWithError error: NSError) {
45 | guard let expectation = asyncExpectation else {
46 | XCTFail("Set expectation in test")
47 | return
48 | }
49 |
50 | failedWithError = error
51 | expectation.fulfill()
52 | }
53 |
54 | func bridgeAuthenticator(_ authenticator: BridgeAuthenticator, didFinishAuthentication username: String) {
55 | guard let expectation = asyncExpectation else {
56 | XCTFail("Set expectation in test")
57 | return
58 | }
59 |
60 | finishWithUsername = username
61 | expectation.fulfill()
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/SwiftyHue iOSTests/BridgeFinderConsumer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BridgeFinderConsumer.swift
3 | // SwiftyHue
4 | //
5 | // Created by Nils Lattek on 28.05.16.
6 | //
7 | //
8 |
9 | import XCTest
10 | @testable import SwiftyHue
11 |
12 | class BridgeFinderConsumer: BridgeFinderDelegate {
13 | var resultBridges: [HueBridge]?
14 | var asyncExpectation: XCTestExpectation?
15 |
16 | func bridgeFinder(_ finder: BridgeFinder, didFinishWithResult bridges: [HueBridge]) {
17 | guard let expectation = asyncExpectation else {
18 | XCTFail("Set expectation in test")
19 | return
20 | }
21 |
22 | resultBridges = bridges
23 | expectation.fulfill()
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/SwiftyHue iOSTests/BridgeFinderTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BridgeFinderTests.swift
3 | // SwiftyHue
4 | //
5 | // Created by Nils Lattek on 28.05.16.
6 | //
7 | //
8 |
9 | import XCTest
10 | import Foundation
11 | @testable import SwiftyHue
12 |
13 | class BridgeFinderTests: XCTestCase {
14 |
15 | override func setUp() {
16 | super.setUp()
17 | // Put setup code here. This method is called before the invocation of each test method in the class.
18 | }
19 |
20 | override func tearDown() {
21 | // Put teardown code here. This method is called after the invocation of each test method in the class.
22 | super.tearDown()
23 | }
24 |
25 | func testTriesMultipleScanners() {
26 | let validator = TestBadValidator()
27 | let finder = BridgeFinder(validator: validator, scannerClasses: [TestScanner1.self, TestScanner2.self])
28 | let consumer = BridgeFinderConsumer()
29 | finder.delegate = consumer
30 | consumer.asyncExpectation = expectation(description: "performFind")
31 |
32 | finder.start()
33 |
34 | waitForExpectations(timeout: 1) { (error) in
35 | if let error = error {
36 | XCTFail("\(error)")
37 | }
38 |
39 | XCTAssertNotNil(TestScanner1.calledAt)
40 | XCTAssertNotNil(TestScanner2.calledAt)
41 | XCTAssertTrue(TestScanner1.calledAt!.compare(TestScanner2.calledAt!) == ComparisonResult.orderedAscending)
42 | XCTAssertEqual(consumer.resultBridges!.count, 0)
43 | }
44 | }
45 |
46 | func testValidateIps() {
47 | let validator = TestBadValidator()
48 | TestScanner1.results = ["127.0.0.1", "192.168.2.1"]
49 | TestScanner2.results = ["192.168.2.2"]
50 | let finder = BridgeFinder(validator: validator, scannerClasses: [TestScanner1.self, TestScanner2.self])
51 | let consumer = BridgeFinderConsumer()
52 | finder.delegate = consumer
53 | consumer.asyncExpectation = expectation(description: "performFind")
54 |
55 | finder.start()
56 |
57 | waitForExpectations(timeout: 1) { (error) in
58 | if let error = error {
59 | XCTFail("\(error)")
60 | }
61 | XCTAssertEqual(validator.calledForIps.count, 3)
62 | XCTAssertEqual(validator.calledForIps.first!, "192.168.2.1")
63 | XCTAssertEqual(validator.calledForIps.last!, "192.168.2.2")
64 | XCTAssertEqual(consumer.resultBridges!.count, 0)
65 | }
66 | }
67 |
68 | func testValidateIpsWithSuccess() {
69 | let validator = TestGoodValidator()
70 | TestScanner1.results = ["127.0.0.1", "192.168.2.1"]
71 | TestScanner2.results = ["192.168.2.2"]
72 | let finder = BridgeFinder(validator: validator, scannerClasses: [TestScanner1.self, TestScanner2.self])
73 | let consumer = BridgeFinderConsumer()
74 | finder.delegate = consumer
75 | consumer.asyncExpectation = expectation(description: "performFind")
76 |
77 | finder.start()
78 |
79 | waitForExpectations(timeout: 1) { (error) in
80 | if let error = error {
81 | XCTFail("\(error)")
82 | }
83 | XCTAssertEqual(validator.calledForIps.count, 2)
84 | XCTAssertEqual(validator.calledForIps.first!, "192.168.2.1")
85 | XCTAssertEqual(validator.calledForIps.last!, "127.0.0.1")
86 | XCTAssertEqual(consumer.resultBridges!.count, 2)
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/SwiftyHue iOSTests/BridgeResultParserTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BridgeResultParserTests.swift
3 | // SwiftyHue
4 | //
5 | // Created by Nils Lattek on 28.05.16.
6 | //
7 | //
8 |
9 | import XCTest
10 | @testable import SwiftyHue
11 |
12 | class BridgeResultParserTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testPerform() {
25 | let path = Bundle(for: BridgeResultParserTests.self).path(forResource: "bridge_response", ofType: "xml")!
26 | let xml = try! Data(contentsOf: URL(fileURLWithPath: path))
27 | let parser = BridgeResultParser(xmlData: xml)
28 |
29 | let asyncExpectation = expectation(description: "parseBridgeXML")
30 | parser.parse({ (bridge) in
31 | XCTAssertEqual(bridge.ip, "192.168.1.130")
32 | XCTAssertEqual(bridge.deviceType, "urn:schemas-upnp-org:device:Basic:1")
33 | XCTAssertEqual(bridge.friendlyName, "Philips hue (192.168.1.130)")
34 | XCTAssertEqual(bridge.modelDescription, "Philips hue Personal Wireless Lighting")
35 | XCTAssertEqual(bridge.modelName, "Philips hue bridge 2012")
36 | XCTAssertEqual(bridge.serialNumber, "001788102201")
37 | XCTAssertEqual(bridge.UDN, "uuid:2f402f80-da50-11e1-9b23-001788102201")
38 | XCTAssertEqual(bridge.icons.count, 2)
39 | XCTAssertEqual(bridge.icons.first?.mimetype, "image/png")
40 | XCTAssertEqual(bridge.icons.first?.height, 48)
41 | XCTAssertEqual(bridge.icons.first?.width, 48)
42 | XCTAssertEqual(bridge.icons.first?.name, "hue_logo_0.png")
43 | asyncExpectation.fulfill()
44 | }, failure: { (error) in
45 |
46 | })
47 |
48 | self.waitForExpectations(timeout: 2, handler: nil)
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/SwiftyHue iOSTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/SwiftyHue iOSTests/TestBadValidator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // File.swift
3 | // SwiftyHue
4 | //
5 | // Created by Nils Lattek on 28.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | @testable import SwiftyHue
11 |
12 | class TestBadValidator: BridgeValidator {
13 | var calledForIps = [String]()
14 |
15 | override func validate(_ ip: String, success: (bridge: HueBridge) -> Void, failure: (error: NSError) -> Void) {
16 | calledForIps.append(ip)
17 | failure(error: NSError(domain: "test", code: 500, userInfo: [NSLocalizedDescriptionKey: "Validation always fails"]))
18 | }
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/SwiftyHue iOSTests/TestGoodValidator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestGoodValidator.swift
3 | // SwiftyHue
4 | //
5 | // Created by Nils Lattek on 28.05.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | @testable import SwiftyHue
11 |
12 | class TestGoodValidator: BridgeValidator {
13 | var calledForIps = [String]()
14 |
15 | override func validate(_ ip: String, success: (bridge: HueBridge) -> Void, failure: (error: NSError) -> Void) {
16 | calledForIps.append(ip)
17 | success(bridge: HueBridge(ip: ip, deviceType: "test device", friendlyName: "name", modelDescription: "model", modelName: "model", serialNumber: "serial", UDN: "udn", icons: []))
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/SwiftyHue iOSTests/TestScanner1.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestScanner1.swift
3 | // SwiftyHue
4 | //
5 | // Created by Nils Lattek on 28.05.16.
6 | //
7 | //
8 |
9 | @testable import SwiftyHue
10 |
11 | class TestScanner1: NSObject, Scanner {
12 | weak var delegate: ScannerDelegate?
13 | static var results = [String]()
14 | static var calledAt: Date?
15 |
16 | required init(delegate: ScannerDelegate? = nil) {
17 | self.delegate = delegate
18 | super.init()
19 | }
20 |
21 | func start() {
22 | TestScanner1.calledAt = Date()
23 | delegate?.scanner(self, didFinishWithResults: TestScanner1.results)
24 | }
25 |
26 | func stop() {
27 |
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/SwiftyHue iOSTests/TestScanner2.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestScanner2.swift
3 | // SwiftyHue
4 | //
5 | // Created by Nils Lattek on 28.05.16.
6 | //
7 | //
8 |
9 | @testable import SwiftyHue
10 |
11 | class TestScanner2: NSObject, Scanner {
12 | weak var delegate: ScannerDelegate?
13 | static var results = [String]()
14 | static var calledAt: Date?
15 |
16 | required init(delegate: ScannerDelegate? = nil) {
17 | self.delegate = delegate
18 | super.init()
19 | }
20 |
21 | func start() {
22 | TestScanner2.calledAt = Date()
23 | delegate?.scanner(self, didFinishWithResults: TestScanner2.results)
24 | }
25 |
26 | func stop() {
27 |
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/SwiftyHue iOSTests/bridge_response.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 1
4 | 0
5 |
6 | http://192.168.1.130:80/
7 |
8 | urn:schemas-upnp-org:device:Basic:1
9 | Philips hue (192.168.1.130)
10 | Royal Philips Electronics
11 | http://www.philips.com
12 | Philips hue Personal Wireless Lighting
13 | Philips hue bridge 2012
14 | 929000226503
15 | http://www.meethue.com
16 | 001788102201
17 | uuid:2f402f80-da50-11e1-9b23-001788102201
18 | index.html
19 |
20 |
21 | image/png
22 | 48
23 | 48
24 | 24
25 | hue_logo_0.png
26 |
27 |
28 | image/png
29 | 120
30 | 120
31 | 24
32 | hue_logo_3.png
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/SwiftyHue macOSTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/SwiftyHue.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | //: Playground - noun: a place where people can play
2 |
3 | import UIKit
4 |
5 | var str = "Hello, playground"
6 |
7 | protocol SensorConfigProvider {
8 | associatedtype SensorConfigType: SensorConfig
9 |
10 | var config: SensorConfigType {get}
11 | }
12 |
13 | protocol SensorStateProvider {
14 | associatedtype SensorStateType: SensorState
15 |
16 | var state: SensorStateType {get}
17 | }
18 |
19 | func ==(lhs: GenericFlagSensor, rhs: GenericFlagSensor) -> Bool {
20 | return lhs.id != rhs.id
21 | }
22 |
23 | protocol Sensor {
24 |
25 | var id: String {get}
26 | var name: String {get}
27 |
28 | }
29 |
30 | protocol SensorConfig {
31 |
32 | }
33 |
34 | protocol SensorState {
35 |
36 | }
37 |
38 | class GenericFlagSensor: Sensor, SensorConfigProvider, SensorStateProvider, Equatable {
39 |
40 | typealias SensorConfigType = GenericFlagSensorConfig
41 | typealias SensorStateType = GenericFlagSensorState
42 |
43 | var id: String
44 | var name: String
45 | var config: GenericFlagSensorConfig
46 | var state: GenericFlagSensorState
47 |
48 | init() {
49 |
50 | id = ""
51 | name = ""
52 | config = GenericFlagSensorConfig()
53 | state = GenericFlagSensorState()
54 |
55 | }
56 | }
57 |
58 |
59 |
60 | class GenericFlagSensorConfig: SensorConfig {
61 |
62 | init(){}
63 | }
64 |
65 | class GenericFlagSensorState: SensorState {
66 |
67 | init(){}
68 |
69 | }
70 |
71 | // TestCode
72 |
73 | var mySensors: GenericFlagSensor = GenericFlagSensor()
74 |
75 | var nsdict: NSDictionary = ["1": mySensors]
76 |
77 | var dict: [String: GenericFlagSensor] = ["1": mySensors]
78 |
79 | print((nsdict as! [String: GenericFlagSensor]) == dict)
80 |
--------------------------------------------------------------------------------
/SwiftyHue.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/SwiftyHue.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # Be sure to run `pod lib lint SwiftyHue.podspec' to ensure this is a
3 | # valid spec before submitting.
4 | #
5 | # Any lines starting with a # are optional, but their use is encouraged
6 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
7 | #
8 |
9 | Pod::Spec.new do |s|
10 | s.name = "SwiftyHue"
11 | s.version = "0.5.9"
12 | s.summary = "Philips Hue SDK written in swift."
13 |
14 | # This description is used to generate tags and improve search results.
15 | # * Think: What does it do? Why did you write it? What is the focus?
16 | # * Try to keep it short, snappy and to the point.
17 | # * Write the description between the DESC delimiters below.
18 | # * Finally, don't worry about the indent, CocoaPods strips it!
19 | s.description = "Philips Hue SDK written in swift. Work in progress."
20 |
21 | s.homepage = "https://github.com/Spriter/SwiftyHue.git"
22 | # s.screenshots = "www.example.com/screenshots_1", "www.example.com/screenshots_2"
23 | s.license = 'MIT'
24 | s.authors = { "Marcel Dittmann" => "marceldittmann@gmx.de", "Jerome Schmitz" => "jerome.schmitz@gmx.net", "Nils Lattek" => "nilslattek@gmail.com" }
25 | s.source = { :git => "https://github.com/Spriter/SwiftyHue.git", :tag => "0.5.9" }
26 |
27 | # s.social_media_url = 'https://twitter.com/'
28 |
29 | s.ios.deployment_target = '9.0'
30 | s.tvos.deployment_target = '9.0'
31 | s.osx.deployment_target = '10.11'
32 |
33 | s.pod_target_xcconfig = { 'ENABLE_TESTABILITY[config=Debug]' => 'YES' }
34 | s.source_files = 'Sources/SwiftyHue.h'
35 |
36 | s.swift_version = '5.0'
37 |
38 | s.subspec 'Base' do |base|
39 |
40 | base.ios.deployment_target = '9.0'
41 | base.tvos.deployment_target = '9.0'
42 | base.watchos.deployment_target = '2.2'
43 | base.osx.deployment_target = '10.11'
44 |
45 | base.source_files = 'Sources/Base/**/*.{h,swift}'
46 | base.dependency 'Alamofire', '4.8.0'
47 | base.dependency 'Gloss', '3.1.0'
48 | end
49 |
50 | s.subspec 'BridgeServices' do |bridgeservices|
51 | bridgeservices.source_files = 'Sources/BridgeServices/**/*.{h,swift}'
52 |
53 | bridgeservices.ios.deployment_target = '9.0'
54 | bridgeservices.tvos.deployment_target = '9.0'
55 | bridgeservices.osx.deployment_target = '10.11'
56 |
57 | bridgeservices.dependency 'Alamofire', '4.8.0'
58 | bridgeservices.dependency 'Gloss', '3.1.0'
59 | bridgeservices.dependency 'CocoaAsyncSocket', '7.6.3'
60 |
61 | end
62 |
63 | end
64 |
--------------------------------------------------------------------------------
/SwiftyHue.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SwiftyHue.xcodeproj/xcshareddata/xcschemes/SwiftyHue iOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
52 |
53 |
59 |
60 |
66 |
67 |
68 |
69 |
71 |
72 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/SwiftyHue.xcodeproj/xcshareddata/xcschemes/SwiftyHue macOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
52 |
53 |
59 |
60 |
66 |
67 |
68 |
69 |
71 |
72 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/SwiftyHue.xcodeproj/xcshareddata/xcschemes/SwiftyHue tvOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
52 |
53 |
59 |
60 |
66 |
67 |
68 |
69 |
71 |
72 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/SwiftyHue.xcodeproj/xcshareddata/xcschemes/SwiftyHue watchOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
52 |
53 |
59 |
60 |
66 |
67 |
68 |
69 |
71 |
72 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/SwiftyHue.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
12 |
13 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/SwiftyHue.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | if ! command -v carthage > /dev/null; then
4 | printf 'Carthage is not installed.\n'
5 | printf 'See https://github.com/Carthage/Carthage for install instructions.\n'
6 | exit 1
7 | fi
8 |
9 | carthage update
10 |
--------------------------------------------------------------------------------