{"id":16737938,"url":"https://github.com/tatey/lifxhttpkit","last_synced_at":"2025-11-11T20:30:35.371Z","repository":{"id":33740870,"uuid":"37395559","full_name":"tatey/LIFXHTTPKit","owner":"tatey","description":"A nice iOS/watchOS/macOS framework for interacting with the LIFX HTTP API that has no external dependencies.","archived":false,"fork":false,"pushed_at":"2021-01-11T23:51:34.000Z","size":226,"stargazers_count":40,"open_issues_count":3,"forks_count":9,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-03-17T13:56:46.293Z","etag":null,"topics":["http-client","ios","lifx","macos","swift","swift-library","watchos"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tatey.png","metadata":{"files":{"readme":"README.markdown","changelog":"CHANGELOG.markdown","contributing":"CONTRIBUTING.markdown","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-06-14T02:09:16.000Z","updated_at":"2022-12-02T16:25:20.000Z","dependencies_parsed_at":"2022-08-26T12:11:59.966Z","dependency_job_id":null,"html_url":"https://github.com/tatey/LIFXHTTPKit","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tatey%2FLIFXHTTPKit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tatey%2FLIFXHTTPKit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tatey%2FLIFXHTTPKit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tatey%2FLIFXHTTPKit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tatey","download_url":"https://codeload.github.com/tatey/LIFXHTTPKit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244164866,"owners_count":20409002,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["http-client","ios","lifx","macos","swift","swift-library","watchos"],"created_at":"2024-10-13T00:28:33.056Z","updated_at":"2025-11-11T20:30:35.338Z","avatar_url":"https://github.com/tatey.png","language":"Swift","readme":"# LIFXHTTPKit [![GitHub release](https://img.shields.io/github/release/tatey/LIFXHTTPKit.svg)](https://github.com/tatey/LIFXHTTPKit/releases/latest) [![GitHub license](https://img.shields.io/github/license/tatey/LIFXHTTPKit.svg)](https://raw.githubusercontent.com/tatey/LIFXHTTPKit/master/LICENSE.txt) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n\nA nice iOS/watchOS/macOS framework for interacting with the [LIFX HTTP API](http://api.developer.lifx.com/docs)\nthat has no external dependencies. Suitable for use inside extensions.\n\nUsed by the [official LIFX iOS](https://itunes.apple.com/us/app/lifx/id657758311?mt=8) app and an open source Mac app, [Lighting](https://github.com/tatey/Lighting).\n\n*NOTE: This is not an official LIFX project.*\n\n## Build Dependencies\n\n* Swift 3.0 (Xcode 8.3+)\n* iOS 8.2+\n* macOS 10.10+\n* watchOS 2+\n\nLooking for an earlier version of Swift?\n\n* Use [2.0.0](https://github.com/tatey/LIFXHTTPKit/releases/tag/2.0.0) for Swift 2.3\n* Use [1.0.0](https://github.com/tatey/LIFXHTTPKit/releases/tag/1.0.0) for Swift 2.2\n* Use [0.0.2](https://github.com/tatey/LIFXHTTPKit/releases/tag/0.0.2) for Swift 1.3\n\n## Installation\n\n### [Carthage](https://github.com/Carthage/Carthage)\n\nAdd the following to your Cartfile:\n\n```\ngithub \"tatey/LIFXHTTPKit\"\n```\n\nThen run `$ carthage update`.\n\nFollow the current instructions in [Carthage's README](https://github.com/Carthage/Carthage)\nfor up to date installation instructions.\n\n## Quick Usage\n\nPower on all the lights.\n\n``` swift\nlet client = Client(accessToken: \"c87c73a896b554367fac61f71dd3656af8d93a525a4e87df5952c6078a89d192\")\nclient.fetch()\nlet all = client.allLightTarget()\nall.setPower(true)\n```\n\nToggle power on one light.\n\n``` swift\nif let lightTarget = all.toLightTargets().first() {\n  lightTarget.setPower(!lightTarget.power)\n}\n```\n\nRestore a scene.\n\n``` swift\nif let scene = client.scenes.first {\n  let lightTarget = client.lightTargetWithSelector(scene.toSelector())\n  lightTarget.restoreState()\n}\n```\n\nUse a closure to find out when the request completes.\n\n``` swift\nlightTarget.setPower(true) { (results, error) in\n  if error != nil {\n    println(error)\n  } else {\n    println(results)\n  }\n}\n```\n\nUse a closure to observer changes to lights.\n\n``` swift\nlet observer = all.addObserver {\n  if all.power {\n    button.titleLabel?.text = \"Turn Off\"\n  } else {\n    button.titleLabel?.text = \"Turn On\"\n  }\n}\n```\n\n...and remove the observer when you're done.\n\n``` swift\nall.removeObserver(observer)\n```\n\nGet the light's state.\n\n``` swift\nlightTarget.selector // =\u003e \u003cLightTargetSelector type: \"id\", value: \"d3b2f2d97452\"\u003e\nlightTarget.power // =\u003e true\nlightTarget.brightness // =\u003e 0.5\nlightTarget.color // =\u003e \u003cColor hue: 180.0, saturation: 1.0, kelvin: 3500\u003e\nlightTarget.label // =\u003e \"Lamp 1\"\n```\n\n## Concepts\n\nLIFXHTTPKit has been built with macOS and iOS apps in mind. These APIs\nmake it easy to consume the LIFX HTTP API without worrying about the specifics\nof HTTP or maintaining state.\n\nKeep these concepts in the back of your mind when using LIFXHTTPKit:\n\n1. Everything is a collection. If you're dealing with one light, it's just a\n   collection with one element. If you're dealing with many lights, it's a\n   collection with many elements. Collections can be sliced into smaller collections.\n   Each collection is a new instance and they're known as a `LightTarget`.\n2. Everything is asynchronous and optimistic. If you tell a light target to power on,\n   then the cached property is immediately updated and observers are notified.\n   If there is a failure the property reverts back to is original value. Operations\n   are handled serially, in-order, and in a background queue.\n3. Observers are closure based and notify listeners when state changes. Binding views\n   to state using observers means you can consolidate your view logic into discrete\n   methods that respond to network and local changes.\n4. Light state is maintained by an instance of `Client` and shared between all\n   instances of `LightTarget`. If you power on one light target then all light\n   targets which share the same underlying light are notified of the change.\n\n## Detailed Usage\n\n`Client` and `LightTarget` are the core classes of LIFXHTTPKit. Clients are\nconfigured with an access token and light targets represent one or many addressable\nlights.\n\n``` swift\nlet client = Client(accessToken: \"c87c73a896b554367fac61f71dd3656af8d93a525a4e87df5952c6078a89d192\")\nclient.fetch(completionHandler: { (error: NSError?) in -\u003e Void\n  // Error is nil if everything is A-OK.\n})\n```\n\nLight targets are instantiated using selectors which are identifiers for\naddressing lights. They are a first class concept in LIFXHTTPKit and several\nconvenience methods offer quick access.\n\nThe default light target is known as \"all\" and it addresses all of the\nlights associated with the client.\n\n``` swift\nlet all = client.allLightTarget()\nall.setPower(true)\n```\n\nLight targets can be sliced into smaller light targets. The all light target\ncan be turned into many individual light targets for fine-grained control.\n\n``` swift\nlet lightTargets = all.toLightTargets()\nfor lightTarget in lightTarget {\n  lightTarget.setPower(true)\n}\n```\n\nLight targets can be inspected at any time based on in-memory cache.\n\n``` swift\nlightTarget.selector // =\u003e \u003cLightTargetSelector type: \"all\", value: \"\"\u003e\nlightTarget.power // =\u003e true\nlightTarget.brightness // =\u003e 0.5\nlightTarget.color // =\u003e \u003cColor hue: 180.0, saturation: 1.0, kelvin: 3500\u003e\nlightTarget.label // =\u003e \"Lamp 1\"\nlightTarget.connected // =\u003e true\nlightTarget.count // =\u003e 5\nlightTarget.lights.first?.group // =\u003e \u003cGroup id: \"1c8de82b81f445e7cfaafae49b259c71\", name: \"Lounge\"\u003e\nlightTarget.lights.first?.location // =\u003e \u003cLocation id: \"1d6fe8ef0fde4c6d77b0012dc736662c\", name: \"Home\"\u003e\nlightTarget.touchedAt // =\u003e 2015-12-09 04:02:41 +0000\n```\n\nThe in-memory cache is updated when the client fetches, or an operation is\nperformed. The results of the operation are inspected and lights which\nhave become disconnected are marked appropriately.\n\n### Selectors\n\nAny light target can be sliced into a light, group or location light target\nusing these convenience methods.\n\n``` swift\n// Get all lights associated with the account\nlet all = client.allLightTarget()\n\n// Lights\nlet lights = all.toLightTargets()\nfor light in lights {\n  light.setBrightness(0.5)\n}\n\n// Groups\nlet groups = all.toGroupTargets()\nfor group in groups {\n  group.setBrightness(0.5)\n}\n\n// Locations\nlet locations = all.toLocationTargets()\nfor location in locations {\n  location.setBrightness(0.5)\n}\n```\n\nAlternatively instantiate a light target using a custom selector.\n\n``` swift\nlet selector = LightTargetSelector(type: .GroupID, value: \"1c8de82b81f445e7cfaafae49b259c71\")\nlet lights = client.lightTargetWithSelector(selector)\nlights.setBrightness(0.5)\n```\n\nSupported types are `.All`, `.ID`, `.GroupID`, `.LocationID`, and `.SceneID`.\n\n### Scenes\n\nScenes are like a virtual group with a preset. Users create scenes with the official\nsuite of LIFX apps.\n\nWhen used as a virtual group scenes let you address an arbitrary collection of lights.\nThis works great for creating nested groups or combining groups beyond their physical\nlocation. You use them like normal light targets.\n\n``` swift\nif let scene = client.scenes.first {\n  let lightTarget = client.lightTargetWithSelector(scene.toSelector())\n  lightTarget.setPower(true)\n}\n```\n\nWhen used as a preset you can restore the state of the virtual group as intended by\nthe creator of the scene. There is a special method called `restoreState` which\noptimistically updates the local in-memory cache as well as making the appropriate\nrequest to the LIFX HTTP API. All of this happens in a single operation.\n\n``` swift\nif let scene = client.scenes.first {\n  let lightTarget = client.lightTargetWithSelector(scene.toSelector())\n  lightTarget.restoreState()\n}\n```\n\n### Observers\n\nUse observers to opt-in to light target state changes. State may change\nas the result of a network response, or a locally initiated operation.\nEither way, you're less likely to have bugs if you place your logic\nfor updating views here.\n\n``` swift\nclass LightView: NSView {\n  // ...\n\n  var observer: LightTargetObserver?\n  var lightTarget: LightTarget\n\n  func setupObserver()\n    observer = lightTarget.addObserver({ () -\u003e Void\n      DispatchQueue.main.async {\n        self.layer?.backgroundColor = self.lightTarget.color\n      }\n    })\n  }\n\n  deinit {\n    if let observer = self.observer {\n      lightTarget.removeObserver(observer)\n    }\n  }\n\n  // ...\n}\n```\n\nKeep these things in the back of your mind when using observers:\n\n* Observers may be notified in the background queue of the client. You can use\n  `DispatchQueue` to jump to a different queue.\n* Observers must be explicitly removed to prevent memory leaks. The destructor\n  is a good place to remove an observer in the object lifecycle. You can\n  add as many observers as you want as long as you remove them when you're done.\n\n### Get Power\n\nDetermine if the light target is powered on. `true` if any of the `connected`\nlights in the light target are powered on.\n\n``` swift\nlightTarget.power // =\u003e true\n```\n\n### Set Power\n\nTurn lights on or off. `true` to turn on, `false` to turn off. The `duration`\nis optional and defaults to `0.5`. The duration controls the length of time\nit takes for the light to change from on to off, or vise versa.\n\n``` swift\nlightTarget.setPower(true, duration: 0.5, completionHandler: { (results: [Result], error: NSError?) -\u003e Void\n  // println(results)\n})\n```\n\n### Get Brightness\n\nReturns the average of the brightness for connected lights if the light target\ncontains mixed brightnesses. A brightness of 0% is `0.0` and a brightness of\n100% is `1.0`.\n\n``` swift\nlightTarget.brightness // =\u003e 0.5\n```\n\nYou can inspect an individual light's brightness instead of using the average in\nmixed groups. See [Get Lights](#get-lights).\n\n### Set Brightness\n\nSet the brightness of the lights. A brightness of 75% is `0.75`. The `duration`\nis optional and defaults to `0.5`. \n\n``` swift\nlightTarget.setBrightness(1.0, duration: 0.5, completionHandler: { (results: [Result], error: NSError?) -\u003e Void\n  // println(results)\n})\n```\n\n### Get Color\n\nReturns the average of the colors for connected lights if the light target\ncontains mixed colors.\n\n``` swift\nlightTarget.color // =\u003e \u003cColor hue: 180.0, saturation: 1.0, kelvin: 3500\u003e\n```\n\nLIFX lights represent color using hue/saturation and whites using kelvin.\nDetermine if a light is white or color using these predicates.\n\n``` swift\nlet color = lightTarget.color\ncolor.isWhite // =\u003e false\ncolor.isColor // =\u003e true\n```\n\nYou can inspect an individual light's color instead of using the average in mixed\ngroups. See [Get Lights](#get-lights).\n\n### Set Color\n\nSets the color of the lights. The `duration` is optional and defaults to `0.5`.\n\n``` swift\nlet color = Color.color(hue: 180.0, saturation: 1.0)\nlightTarget.setColor(color, duration: 0.5, completionHandler: { (results: [Result], error: NSError?) -\u003e Void\n  // println(results)\n})\n\nlet white = Color.white(kelvin: 3500)\nlightTarget.setColor(color, duration: 0.5, completionHandler: { (results: [Result], error: NSError?) -\u003e Void\n  // println(results)\n})\n```\n\n### Set State (Color, Brightness, and Power Simultaneously)\n\nSets the color, brightness, and power of the lights in one operation. The `duration` is optional and defaults to `0.5`.\nAll other arguments except are optional and default to `nil`. A `nil` value is the equivalent to leaving the\nvalue unchanged.\n\n``` swift\nlet color = Color.color(hue: 180.0, saturation: 1.0)\nlightTarget.setState(color, brightness: 0.75, duration: 0.5, power: true, completionHandler: { (results: [Result], error: NSError?) -\u003e Void\n  // println(results)\n})\n```\n\n### Restore State\n\n**Scenes Only**: Sets the state of the lights as defined by the backing scene. The `duration` is optional and\ndefaults to `0.5`.\n\nCalling this method on a non-scene based light target will set the error argument in the `completionHandler`\ncallback.\n\n``` swift\nlightTarget.restoreState(0.5, completionHandler: { (results: [Result], error: NSError?) -\u003e Void\n  // println(results)\n})\n```\n\n### Get Label\n\nReturns the label for the light target. If the light target is a group or\nlocation then the label will be derived from the group or location.\n\n``` swift\nlightTarget.label // =\u003e \"Lamp 1\"\n```\n\nThe \"all\" light target will always return `\"All\"` as the label.\n\n### Get Connected\n\nDetermines if the lights are connected and reachable over the internet.\n`true` if at least one light addressed by the light target is reachable.\n`false` if all of the lights are unreachable.\n\n``` swift\nlightTarget.connected // =\u003e true\n```\n\nThe connected property is updated each time an operation is performed\nusing the results returned in the response.\n\n### Get Count\n\nReturns the number of known lights addressable by the light target.\n\n``` swift\nlightTarget.count // =\u003e 5\n```\n\n### Get Lights\n\nInspect the lights addressable by the light target. If you're dealing\nwith a mixed group you can inspect each light individually.\n\n``` swift\nfor light in lightTarget.lights {\n  println(light.id)\n}\n```\n\nA light has the following properties:\n\n``` swift\nlight.id // =\u003e \"d3b2f2d97452\"\nlight.power // =\u003e true\nlight.brightness // =\u003e 0.5\nlight.color // =\u003e \u003cColor hue: 180.0, saturation: 1.0, kelvin: 3500\u003e\nlight.label // =\u003e \"Lamp 1\"\nlight.connected // =\u003e true\nlight.group // =\u003e \u003cGroup id: \"1c8de82b81f445e7cfaafae49b259c71\", name: \"Lounge\"\u003e\nlight.location // =\u003e \u003cLocation id: \"1d6fe8ef0fde4c6d77b0012dc736662c\", name: \"Home\"\u003e\nlight.productInfo // =\u003e \u003cProductInformation productName: \"LIFX Color 1000\", manufacturer: \"LIFX\", capabilities: \u003cCapabilities hasColor: true, hasIR: false, hasMultiZone: false\u003e\u003e\n```\n\nThe `group` and `location` properties are optional as they are not required by\nthe LIFX protocol. In practice these properties are always set.\n\n## Testing\n\nFirst, copy the example configuration file.\n\n    $ cp Tests/Secrets.example.plist Tests/Secrets.plist\n\nThen, paste a personal access token into the copied configuration file. The\naccess token must belong to an account that has at least one connected light.\nYou can generate a personal access tokens at https://cloud.lifx.com/settings.\n\nFinally, run tests by selecting \"Product \u003e Tests\" from the menu bar, or use the\n\"⌘ + U\" shortcut.\n\n## Copyright\n\nCopyright (c) 2015-2016 Tate Johnson. All rights reserved. Licensed under the MIT license.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftatey%2Flifxhttpkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftatey%2Flifxhttpkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftatey%2Flifxhttpkit/lists"}