lifx-lan 0.5.0.1 → 0.5.1
raw patch · 5 files changed
+1928/−14 lines, 5 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Lifx.Lan: data LifxT m a
+ Lifx.Internal.Product: Features :: Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Maybe (Word16, Word16) -> Bool -> Features
+ Lifx.Internal.Product: PartialFeatures :: Maybe Bool -> Maybe Bool -> Maybe Bool -> Maybe Bool -> Maybe Bool -> Maybe Bool -> Maybe Bool -> Maybe Bool -> Maybe (Word16, Word16) -> Maybe Bool -> PartialFeatures
+ Lifx.Internal.Product: ProductInfo :: Word32 -> Text -> PartialFeatures -> [Upgrade] -> ProductInfo
+ Lifx.Internal.Product: Upgrade :: Word16 -> Word16 -> PartialFeatures -> Upgrade
+ Lifx.Internal.Product: VendorInfo :: Word32 -> Text -> Features -> [ProductInfo] -> VendorInfo
+ Lifx.Internal.Product: [$sel:buttons:Features] :: Features -> Bool
+ Lifx.Internal.Product: [$sel:buttons:PartialFeatures] :: PartialFeatures -> Maybe Bool
+ Lifx.Internal.Product: [$sel:chain:Features] :: Features -> Bool
+ Lifx.Internal.Product: [$sel:chain:PartialFeatures] :: PartialFeatures -> Maybe Bool
+ Lifx.Internal.Product: [$sel:color:Features] :: Features -> Bool
+ Lifx.Internal.Product: [$sel:color:PartialFeatures] :: PartialFeatures -> Maybe Bool
+ Lifx.Internal.Product: [$sel:defaults:VendorInfo] :: VendorInfo -> Features
+ Lifx.Internal.Product: [$sel:extendedMultizone:Features] :: Features -> Bool
+ Lifx.Internal.Product: [$sel:extendedMultizone:PartialFeatures] :: PartialFeatures -> Maybe Bool
+ Lifx.Internal.Product: [$sel:features:ProductInfo] :: ProductInfo -> PartialFeatures
+ Lifx.Internal.Product: [$sel:features:Upgrade] :: Upgrade -> PartialFeatures
+ Lifx.Internal.Product: [$sel:hev:Features] :: Features -> Bool
+ Lifx.Internal.Product: [$sel:hev:PartialFeatures] :: PartialFeatures -> Maybe Bool
+ Lifx.Internal.Product: [$sel:infrared:Features] :: Features -> Bool
+ Lifx.Internal.Product: [$sel:infrared:PartialFeatures] :: PartialFeatures -> Maybe Bool
+ Lifx.Internal.Product: [$sel:major:Upgrade] :: Upgrade -> Word16
+ Lifx.Internal.Product: [$sel:matrix:Features] :: Features -> Bool
+ Lifx.Internal.Product: [$sel:matrix:PartialFeatures] :: PartialFeatures -> Maybe Bool
+ Lifx.Internal.Product: [$sel:minor:Upgrade] :: Upgrade -> Word16
+ Lifx.Internal.Product: [$sel:multizone:Features] :: Features -> Bool
+ Lifx.Internal.Product: [$sel:multizone:PartialFeatures] :: PartialFeatures -> Maybe Bool
+ Lifx.Internal.Product: [$sel:name:ProductInfo] :: ProductInfo -> Text
+ Lifx.Internal.Product: [$sel:name:VendorInfo] :: VendorInfo -> Text
+ Lifx.Internal.Product: [$sel:pid:ProductInfo] :: ProductInfo -> Word32
+ Lifx.Internal.Product: [$sel:products:VendorInfo] :: VendorInfo -> [ProductInfo]
+ Lifx.Internal.Product: [$sel:relays:Features] :: Features -> Bool
+ Lifx.Internal.Product: [$sel:relays:PartialFeatures] :: PartialFeatures -> Maybe Bool
+ Lifx.Internal.Product: [$sel:temperatureRange:Features] :: Features -> Maybe (Word16, Word16)
+ Lifx.Internal.Product: [$sel:temperatureRange:PartialFeatures] :: PartialFeatures -> Maybe (Word16, Word16)
+ Lifx.Internal.Product: [$sel:upgrades:ProductInfo] :: ProductInfo -> [Upgrade]
+ Lifx.Internal.Product: [$sel:vid:VendorInfo] :: VendorInfo -> Word32
+ Lifx.Internal.Product: data Features
+ Lifx.Internal.Product: data PartialFeatures
+ Lifx.Internal.Product: data ProductInfo
+ Lifx.Internal.Product: data Upgrade
+ Lifx.Internal.Product: data VendorInfo
+ Lifx.Internal.Product: instance GHC.Show.Show Lifx.Internal.Product.Features
+ Lifx.Internal.Product: instance GHC.Show.Show Lifx.Internal.Product.PartialFeatures
+ Lifx.Internal.Product: instance GHC.Show.Show Lifx.Internal.Product.ProductInfo
+ Lifx.Internal.Product: instance GHC.Show.Show Lifx.Internal.Product.Upgrade
+ Lifx.Internal.Product: instance GHC.Show.Show Lifx.Internal.Product.VendorInfo
+ Lifx.Internal.ProductInfo: productInfo :: [VendorInfo]
+ Lifx.Lan: Features :: Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Maybe (Word16, Word16) -> Bool -> Features
+ Lifx.Lan: LifxT :: StateT Word8 (ReaderT (Socket, Word32, Int) (ExceptT LifxError m)) a -> LifxT m a
+ Lifx.Lan: Product :: Text -> Word32 -> Features -> Product
+ Lifx.Lan: StateHostFirmware :: Word64 -> Word16 -> Word16 -> StateHostFirmware
+ Lifx.Lan: StateVersion :: Word32 -> Word32 -> StateVersion
+ Lifx.Lan: UnknownProductId :: Word32 -> LifxError
+ Lifx.Lan: UnknownVendorId :: Word32 -> LifxError
+ Lifx.Lan: [$sel:build:StateHostFirmware] :: StateHostFirmware -> Word64
+ Lifx.Lan: [$sel:buttons:Features] :: Features -> Bool
+ Lifx.Lan: [$sel:chain:Features] :: Features -> Bool
+ Lifx.Lan: [$sel:color:Features] :: Features -> Bool
+ Lifx.Lan: [$sel:extendedMultizone:Features] :: Features -> Bool
+ Lifx.Lan: [$sel:features:Product] :: Product -> Features
+ Lifx.Lan: [$sel:hev:Features] :: Features -> Bool
+ Lifx.Lan: [$sel:infrared:Features] :: Features -> Bool
+ Lifx.Lan: [$sel:matrix:Features] :: Features -> Bool
+ Lifx.Lan: [$sel:multizone:Features] :: Features -> Bool
+ Lifx.Lan: [$sel:name:Product] :: Product -> Text
+ Lifx.Lan: [$sel:product:StateVersion] :: StateVersion -> Word32
+ Lifx.Lan: [$sel:productId:Product] :: Product -> Word32
+ Lifx.Lan: [$sel:relays:Features] :: Features -> Bool
+ Lifx.Lan: [$sel:temperatureRange:Features] :: Features -> Maybe (Word16, Word16)
+ Lifx.Lan: [$sel:vendor:StateVersion] :: StateVersion -> Word32
+ Lifx.Lan: [$sel:versionMajor:StateHostFirmware] :: StateHostFirmware -> Word16
+ Lifx.Lan: [$sel:versionMinor:StateHostFirmware] :: StateHostFirmware -> Word16
+ Lifx.Lan: [GetHostFirmware] :: Message StateHostFirmware
+ Lifx.Lan: [GetVersion] :: Message StateVersion
+ Lifx.Lan: data Features
+ Lifx.Lan: data Product
+ Lifx.Lan: data StateHostFirmware
+ Lifx.Lan: data StateVersion
+ Lifx.Lan: getProductInfo :: MonadLifx m => Device -> m Product
+ Lifx.Lan: instance GHC.Classes.Eq Lifx.Lan.StateHostFirmware
+ Lifx.Lan: instance GHC.Classes.Eq Lifx.Lan.StateVersion
+ Lifx.Lan: instance GHC.Classes.Ord Lifx.Lan.StateHostFirmware
+ Lifx.Lan: instance GHC.Classes.Ord Lifx.Lan.StateVersion
+ Lifx.Lan: instance GHC.Generics.Generic Lifx.Lan.StateHostFirmware
+ Lifx.Lan: instance GHC.Generics.Generic Lifx.Lan.StateVersion
+ Lifx.Lan: instance GHC.Show.Show Lifx.Lan.Product
+ Lifx.Lan: instance GHC.Show.Show Lifx.Lan.StateHostFirmware
+ Lifx.Lan: instance GHC.Show.Show Lifx.Lan.StateVersion
+ Lifx.Lan: instance Lifx.Lan.MessageResult Lifx.Lan.StateHostFirmware
+ Lifx.Lan: instance Lifx.Lan.MessageResult Lifx.Lan.StateVersion
+ Lifx.Lan: instance Lifx.Lan.Response Lifx.Lan.StateHostFirmware
+ Lifx.Lan: instance Lifx.Lan.Response Lifx.Lan.StateVersion
+ Lifx.Lan: newtype LifxT m a
Files
- CHANGELOG.md +4/−0
- lifx-lan.cabal +7/−5
- src/Lifx/Internal/Product.hs +56/−0
- src/Lifx/Internal/ProductInfo.hs +1669/−0
- src/Lifx/Lan.hs +192/−9
CHANGELOG.md view
@@ -1,5 +1,9 @@ # Revision history for lifx-lan +## 0.5.1 -- 2021-12-12+- Implement `getProductInfo`.+- Expose `LifxT` constructor.+ ## 0.5.0 -- 2021-08-01 - Fix bug which was causing broadcasting not to work with messages that expect no response.
lifx-lan.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: lifx-lan-version: 0.5.0.1+version: 0.5.1 license: BSD-3-Clause license-file: LICENSE author: George Thomas@@ -16,14 +16,16 @@ library exposed-modules:+ Lifx.Internal.Product+ Lifx.Internal.ProductInfo Lifx.Lan hs-source-dirs: src ghc-options: -Wall build-depends:- base ^>= 4.14,+ base ^>= {4.14, 4.15, 4.16}, binary ^>= 0.8.8,- bytestring ^>= 0.10.8,+ bytestring ^>= {0.10.8, 0.11}, composition ^>= 1.0.2.1, containers ^>= 0.6.2.1, extra ^>= 1.7.1,@@ -33,8 +35,8 @@ random ^>= 1.2.0, safe ^>= 0.3.19, text ^>= 1.2.3,- time ^>= 1.9.3,- transformers ^>= 0.5.6,+ time ^>= {1.9.3, 1.10, 1.11, 1.12, 1.13},+ transformers ^>= {0.5.6, 0.6}, default-language: Haskell2010 default-extensions: AllowAmbiguousTypes
+ src/Lifx/Internal/Product.hs view
@@ -0,0 +1,56 @@+-- | An exact mapping of the types in LIFX's `products.json`. It's easier to just use 'Lifx.Lan.getProductInfo'.+module Lifx.Internal.Product where++import Data.Text (Text)+import Data.Word (Word16, Word32)++data VendorInfo = VendorInfo+ { vid :: Word32+ , name :: Text+ , defaults :: Features+ , products :: [ProductInfo]+ }+ deriving (Show)++data ProductInfo = ProductInfo+ { pid :: Word32+ , name :: Text+ , features :: PartialFeatures+ , upgrades :: [Upgrade]+ }+ deriving (Show)++data PartialFeatures = PartialFeatures+ { hev :: Maybe Bool+ , color :: Maybe Bool+ , chain :: Maybe Bool+ , matrix :: Maybe Bool+ , relays :: Maybe Bool+ , buttons :: Maybe Bool+ , infrared :: Maybe Bool+ , multizone :: Maybe Bool+ , temperatureRange :: Maybe (Word16, Word16)+ , extendedMultizone :: Maybe Bool+ }+ deriving (Show)++data Features = Features+ { hev :: Bool+ , color :: Bool+ , chain :: Bool+ , matrix :: Bool+ , relays :: Bool+ , buttons :: Bool+ , infrared :: Bool+ , multizone :: Bool+ , temperatureRange :: Maybe (Word16, Word16)+ , extendedMultizone :: Bool+ }+ deriving (Show)++data Upgrade = Upgrade+ { major :: Word16+ , minor :: Word16+ , features :: PartialFeatures+ }+ deriving (Show)
+ src/Lifx/Internal/ProductInfo.hs view
@@ -0,0 +1,1669 @@+-- | This is auto-generated - see the "product-gen" script.+module Lifx.Internal.ProductInfo where++import Lifx.Internal.Product++productInfo :: [VendorInfo]+productInfo =+ [ VendorInfo+ { vid = 1+ , name = "LIFX"+ , defaults = Features+ { hev = False+ , color = False+ , chain = False+ , matrix = False+ , relays = False+ , buttons = False+ , infrared = False+ , multizone = False+ , temperatureRange = Nothing+ , extendedMultizone = False+ }+ , products =+ [ ProductInfo+ { pid = 1+ , name = "LIFX Original 1000"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 3+ , name = "LIFX Color 650"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 10+ , name = "LIFX White 800 (Low Voltage)"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just False+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2700+ , 6500+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 11+ , name = "LIFX White 800 (High Voltage)"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just False+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2700+ , 6500+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 15+ , name = "LIFX Color 1000"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 18+ , name = "LIFX White 900 BR30 (Low Voltage)"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just False+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 19+ , name = "LIFX White 900 BR30 (High Voltage)"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just False+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 20+ , name = "LIFX Color 1000 BR30"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 22+ , name = "LIFX Color 1000"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 27+ , name = "LIFX A19"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades =+ [ Upgrade+ { major = 2+ , minor = 80+ , features = PartialFeatures+ { hev = Nothing+ , color = Nothing+ , chain = Nothing+ , matrix = Nothing+ , relays = Nothing+ , buttons = Nothing+ , infrared = Nothing+ , multizone = Nothing+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ }+ ]+ }+ , ProductInfo+ { pid = 28+ , name = "LIFX BR30"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades =+ [ Upgrade+ { major = 2+ , minor = 80+ , features = PartialFeatures+ { hev = Nothing+ , color = Nothing+ , chain = Nothing+ , matrix = Nothing+ , relays = Nothing+ , buttons = Nothing+ , infrared = Nothing+ , multizone = Nothing+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ }+ ]+ }+ , ProductInfo+ { pid = 29+ , name = "LIFX A19 Night Vision"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just True+ , multizone = Just False+ , temperatureRange = Just+ ( 2500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades =+ [ Upgrade+ { major = 2+ , minor = 80+ , features = PartialFeatures+ { hev = Nothing+ , color = Nothing+ , chain = Nothing+ , matrix = Nothing+ , relays = Nothing+ , buttons = Nothing+ , infrared = Nothing+ , multizone = Nothing+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ }+ ]+ }+ , ProductInfo+ { pid = 30+ , name = "LIFX BR30 Night Vision"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just True+ , multizone = Just False+ , temperatureRange = Just+ ( 2500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades =+ [ Upgrade+ { major = 2+ , minor = 80+ , features = PartialFeatures+ { hev = Nothing+ , color = Nothing+ , chain = Nothing+ , matrix = Nothing+ , relays = Nothing+ , buttons = Nothing+ , infrared = Nothing+ , multizone = Nothing+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ }+ ]+ }+ , ProductInfo+ { pid = 31+ , name = "LIFX Z"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just True+ , temperatureRange = Just+ ( 2500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 32+ , name = "LIFX Z"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just True+ , temperatureRange = Just+ ( 2500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades =+ [ Upgrade+ { major = 2+ , minor = 77+ , features = PartialFeatures+ { hev = Nothing+ , color = Nothing+ , chain = Nothing+ , matrix = Nothing+ , relays = Nothing+ , buttons = Nothing+ , infrared = Nothing+ , multizone = Nothing+ , temperatureRange = Nothing+ , extendedMultizone = Just True+ }+ }+ , Upgrade+ { major = 2+ , minor = 80+ , features = PartialFeatures+ { hev = Nothing+ , color = Nothing+ , chain = Nothing+ , matrix = Nothing+ , relays = Nothing+ , buttons = Nothing+ , infrared = Nothing+ , multizone = Nothing+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ }+ ]+ }+ , ProductInfo+ { pid = 36+ , name = "LIFX Downlight"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades =+ [ Upgrade+ { major = 2+ , minor = 80+ , features = PartialFeatures+ { hev = Nothing+ , color = Nothing+ , chain = Nothing+ , matrix = Nothing+ , relays = Nothing+ , buttons = Nothing+ , infrared = Nothing+ , multizone = Nothing+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ }+ ]+ }+ , ProductInfo+ { pid = 37+ , name = "LIFX Downlight"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades =+ [ Upgrade+ { major = 2+ , minor = 80+ , features = PartialFeatures+ { hev = Nothing+ , color = Nothing+ , chain = Nothing+ , matrix = Nothing+ , relays = Nothing+ , buttons = Nothing+ , infrared = Nothing+ , multizone = Nothing+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ }+ ]+ }+ , ProductInfo+ { pid = 38+ , name = "LIFX Beam"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just True+ , temperatureRange = Just+ ( 2500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades =+ [ Upgrade+ { major = 2+ , minor = 77+ , features = PartialFeatures+ { hev = Nothing+ , color = Nothing+ , chain = Nothing+ , matrix = Nothing+ , relays = Nothing+ , buttons = Nothing+ , infrared = Nothing+ , multizone = Nothing+ , temperatureRange = Nothing+ , extendedMultizone = Just True+ }+ }+ , Upgrade+ { major = 2+ , minor = 80+ , features = PartialFeatures+ { hev = Nothing+ , color = Nothing+ , chain = Nothing+ , matrix = Nothing+ , relays = Nothing+ , buttons = Nothing+ , infrared = Nothing+ , multizone = Nothing+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ }+ ]+ }+ , ProductInfo+ { pid = 39+ , name = "LIFX Downlight White to Warm"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just False+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades =+ [ Upgrade+ { major = 2+ , minor = 80+ , features = PartialFeatures+ { hev = Nothing+ , color = Nothing+ , chain = Nothing+ , matrix = Nothing+ , relays = Nothing+ , buttons = Nothing+ , infrared = Nothing+ , multizone = Nothing+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ }+ ]+ }+ , ProductInfo+ { pid = 40+ , name = "LIFX Downlight"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades =+ [ Upgrade+ { major = 2+ , minor = 80+ , features = PartialFeatures+ { hev = Nothing+ , color = Nothing+ , chain = Nothing+ , matrix = Nothing+ , relays = Nothing+ , buttons = Nothing+ , infrared = Nothing+ , multizone = Nothing+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ }+ ]+ }+ , ProductInfo+ { pid = 43+ , name = "LIFX A19"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades =+ [ Upgrade+ { major = 2+ , minor = 80+ , features = PartialFeatures+ { hev = Nothing+ , color = Nothing+ , chain = Nothing+ , matrix = Nothing+ , relays = Nothing+ , buttons = Nothing+ , infrared = Nothing+ , multizone = Nothing+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ }+ ]+ }+ , ProductInfo+ { pid = 44+ , name = "LIFX BR30"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades =+ [ Upgrade+ { major = 2+ , minor = 80+ , features = PartialFeatures+ { hev = Nothing+ , color = Nothing+ , chain = Nothing+ , matrix = Nothing+ , relays = Nothing+ , buttons = Nothing+ , infrared = Nothing+ , multizone = Nothing+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ }+ ]+ }+ , ProductInfo+ { pid = 45+ , name = "LIFX A19 Night Vision"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just True+ , multizone = Just False+ , temperatureRange = Just+ ( 2500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades =+ [ Upgrade+ { major = 2+ , minor = 80+ , features = PartialFeatures+ { hev = Nothing+ , color = Nothing+ , chain = Nothing+ , matrix = Nothing+ , relays = Nothing+ , buttons = Nothing+ , infrared = Nothing+ , multizone = Nothing+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ }+ ]+ }+ , ProductInfo+ { pid = 46+ , name = "LIFX BR30 Night Vision"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just True+ , multizone = Just False+ , temperatureRange = Just+ ( 2500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades =+ [ Upgrade+ { major = 2+ , minor = 80+ , features = PartialFeatures+ { hev = Nothing+ , color = Nothing+ , chain = Nothing+ , matrix = Nothing+ , relays = Nothing+ , buttons = Nothing+ , infrared = Nothing+ , multizone = Nothing+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ }+ ]+ }+ , ProductInfo+ { pid = 49+ , name = "LIFX Mini Color"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 50+ , name = "LIFX Mini White to Warm"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just False+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 6500+ )+ , extendedMultizone = Nothing+ }+ , upgrades =+ [ Upgrade+ { major = 3+ , minor = 70+ , features = PartialFeatures+ { hev = Nothing+ , color = Nothing+ , chain = Nothing+ , matrix = Nothing+ , relays = Nothing+ , buttons = Nothing+ , infrared = Nothing+ , multizone = Nothing+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ }+ ]+ }+ , ProductInfo+ { pid = 51+ , name = "LIFX Mini White"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just False+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2700+ , 2700+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 52+ , name = "LIFX GU10"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 53+ , name = "LIFX GU10"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 55+ , name = "LIFX Tile"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just True+ , matrix = Just True+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 57+ , name = "LIFX Candle"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just True+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 59+ , name = "LIFX Mini Color"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 60+ , name = "LIFX Mini White to Warm"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just False+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 6500+ )+ , extendedMultizone = Nothing+ }+ , upgrades =+ [ Upgrade+ { major = 3+ , minor = 70+ , features = PartialFeatures+ { hev = Nothing+ , color = Nothing+ , chain = Nothing+ , matrix = Nothing+ , relays = Nothing+ , buttons = Nothing+ , infrared = Nothing+ , multizone = Nothing+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ }+ ]+ }+ , ProductInfo+ { pid = 61+ , name = "LIFX Mini White"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just False+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2700+ , 2700+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 62+ , name = "LIFX A19"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 63+ , name = "LIFX BR30"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 64+ , name = "LIFX A19 Night Vision"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just True+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 65+ , name = "LIFX BR30 Night Vision"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just True+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 66+ , name = "LIFX Mini White"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just False+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2700+ , 2700+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 68+ , name = "LIFX Candle"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just True+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 70+ , name = "LIFX Switch"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just False+ , chain = Just False+ , matrix = Just False+ , relays = Just True+ , buttons = Just True+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Nothing+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 71+ , name = "LIFX Switch"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just False+ , chain = Just False+ , matrix = Just False+ , relays = Just True+ , buttons = Just True+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Nothing+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 81+ , name = "LIFX Candle White to Warm"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just False+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2200+ , 6500+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 82+ , name = "LIFX Filament Clear"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just False+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2100+ , 2100+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 85+ , name = "LIFX Filament Amber"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just False+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2000+ , 2000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 87+ , name = "LIFX Mini White"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just False+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2700+ , 2700+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 88+ , name = "LIFX Mini White"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just False+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2700+ , 2700+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 89+ , name = "LIFX Switch"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just False+ , chain = Just False+ , matrix = Just False+ , relays = Just True+ , buttons = Just True+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Nothing+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 90+ , name = "LIFX Clean"+ , features = PartialFeatures+ { hev = Just True+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 91+ , name = "LIFX Color"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 92+ , name = "LIFX Color"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 93+ , name = "LIFX A19 US"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 94+ , name = "LIFX BR30"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 96+ , name = "LIFX Candle White to Warm"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just False+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2200+ , 6500+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 97+ , name = "LIFX A19"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 98+ , name = "LIFX BR30"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 99+ , name = "LIFX Clean"+ , features = PartialFeatures+ { hev = Just True+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 100+ , name = "LIFX Filament Clear"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just False+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2100+ , 2100+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 101+ , name = "LIFX Filament Amber"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just False+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 2000+ , 2000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 109+ , name = "LIFX A19 Night Vision"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just True+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 110+ , name = "LIFX BR30 Night Vision"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just True+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 111+ , name = "LIFX A19 Night Vision"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just True+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 112+ , name = "LIFX BR30 Night Vision Intl"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just True+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just True+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 113+ , name = "LIFX Mini WW US"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just False+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ , ProductInfo+ { pid = 114+ , name = "LIFX Mini WW Intl"+ , features = PartialFeatures+ { hev = Nothing+ , color = Just False+ , chain = Just False+ , matrix = Just False+ , relays = Nothing+ , buttons = Nothing+ , infrared = Just False+ , multizone = Just False+ , temperatureRange = Just+ ( 1500+ , 9000+ )+ , extendedMultizone = Nothing+ }+ , upgrades = []+ }+ ]+ }+ ]
src/Lifx/Lan.hs view
@@ -28,7 +28,7 @@ HSBK (..), Lifx, runLifx,- LifxT,+ LifxT (LifxT), runLifxT, LifxError (..), MonadLifx (..),@@ -36,9 +36,16 @@ -- * Responses StateService (..), Service (..),+ StateHostFirmware (..), StatePower (..),+ StateVersion (..), LightState (..), + -- ** Product info+ getProductInfo,+ Product (..),+ Features (..),+ -- * Low-level deviceFromAddress, encodeMessage,@@ -46,6 +53,7 @@ unLifxT, ) where +import Control.Applicative import Control.Monad import Control.Monad.Except import Control.Monad.Extra@@ -54,10 +62,10 @@ import Control.Monad.Trans.Maybe import Data.Either.Extra import Data.Fixed-import Data.Foldable+import Data.Foldable hiding (product) import Data.Function import Data.Functor-import Data.List+import Data.List hiding (product) import Data.Maybe import Data.Tuple.Extra import Data.Word@@ -72,6 +80,7 @@ getWord16le, getWord32le, getWord64be,+ getWord64le, getWord8, runGetOrFail, skip,@@ -88,8 +97,9 @@ import Data.ByteString qualified as BS import Data.ByteString.Lazy qualified as BL import Data.List.NonEmpty (NonEmpty)-import Data.Map (Map)+import Data.Map (Map, (!?)) import Data.Map.Strict qualified as Map+import Data.Text (Text) import Data.Time ( NominalDiffTime, diffUTCTime,@@ -117,6 +127,12 @@ import System.Random (randomIO) import System.Timeout (timeout) +import Lifx.Internal.Product+import Lifx.Internal.ProductInfo++--TODO RecordDotSyntax can make this and other hiding unnecessary (we could also use "id" instead of "productId"...)+import Prelude hiding (product)+ {- Device -} -- | A LIFX device, such as a bulb.@@ -187,10 +203,14 @@ -- | https://lan.developer.lifx.com/docs/querying-the-device-for-data#getservice---packet-2 -- (you shouldn't need this - use 'discoverDevices') GetService :: Message StateService+ -- | https://lan.developer.lifx.com/docs/querying-the-device-for-data#gethostfirmware---packet-14+ GetHostFirmware :: Message StateHostFirmware -- | https://lan.developer.lifx.com/docs/querying-the-device-for-data#getpower---packet-20 GetPower :: Message StatePower -- | https://lan.developer.lifx.com/docs/changing-a-device#setpower---packet-21 SetPower :: Bool -> Message ()+ -- | https://lan.developer.lifx.com/docs/querying-the-device-for-data#getversion---packet-32+ GetVersion :: Message StateVersion -- | https://lan.developer.lifx.com/docs/querying-the-device-for-data#getcolor---packet-101 GetColor :: Message LightState -- | https://lan.developer.lifx.com/docs/changing-a-device#setcolor---packet-102@@ -218,12 +238,32 @@ } deriving (Eq, Ord, Show, Generic) +-- | https://lan.developer.lifx.com/docs/information-messages#statehostfirmware---packet-15+data StateHostFirmware = StateHostFirmware+ { -- | The timestamp of the firmware that is on the device as an epoch+ build :: Word64+ , -- | The minor component of the firmware version+ versionMinor :: Word16+ , -- | The major component of the firmware version+ versionMajor :: Word16+ }+ deriving (Eq, Ord, Show, Generic)+ -- | https://lan.developer.lifx.com/docs/information-messages#statepower---packet-22 newtype StatePower = StatePower { power :: Word16 } deriving (Eq, Ord, Show, Generic) +-- | https://lan.developer.lifx.com/docs/information-messages#stateversion---packet-33+data StateVersion = StateVersion+ { -- | For LIFX products this value is 1. There may be devices in the future with a different vendor value.+ vendor :: Word32+ , -- | The product id of the device. The available products can be found in our Product Registry.+ product :: Word32+ }+ deriving (Eq, Ord, Show, Generic)+ -- | https://lan.developer.lifx.com/docs/information-messages#lightstate---packet-107 data LightState = LightState { hsbk :: HSBK@@ -240,6 +280,8 @@ | WrongSender Device HostAddress -- expected, then actual | UnexpectedSockAddrType SockAddr | UnexpectedPort PortNumber+ | UnknownVendorId Word32+ | UnknownProductId Word32 deriving (Eq, Ord, Show, Generic) {- Message responses -}@@ -325,6 +367,30 @@ maybe (fail $ "port out of range: " <> show x) pure $ fromIntegralSafe x pure StateService{..} instance MessageResult StateService+instance Response StateHostFirmware where+ expectedPacketType = 15+ messageSize = 20+ getBody = do+ build <- getWord64le+ skip 8+ versionMinor <- getWord16le+ versionMajor <- getWord16le+ pure StateHostFirmware{..}+instance MessageResult StateHostFirmware+instance Response StatePower where+ expectedPacketType = 22+ messageSize = 2+ getBody = StatePower <$> getWord16le+instance MessageResult StatePower+instance Response StateVersion where+ expectedPacketType = 33+ messageSize = 20+ getBody = do+ vendor <- getWord32le+ product <- getWord32le+ skip 4+ pure StateVersion{..}+instance MessageResult StateVersion instance Response LightState where expectedPacketType = 107 messageSize = 52@@ -336,11 +402,6 @@ skip 8 pure LightState{..} instance MessageResult LightState-instance Response StatePower where- expectedPacketType = 22- messageSize = 2- getBody = StatePower <$> getWord16le-instance MessageResult StatePower -- all `Message` response types are instances of `MessageResult` --TODO ImpredicativeTypes:@@ -348,8 +409,10 @@ msgResWitness :: Message r -> Dict (MessageResult r) msgResWitness = \case GetService{} -> Dict+ GetHostFirmware{} -> Dict GetPower{} -> Dict SetPower{} -> Dict+ GetVersion{} -> Dict GetColor{} -> Dict SetColor{} -> Dict SetLightPower{} -> Dict@@ -531,6 +594,12 @@ , packetType = 2 , .. }+ GetHostFirmware{} ->+ Header+ { size = headerSize+ , packetType = 14+ , ..+ } GetPower{} -> Header { size = headerSize@@ -543,6 +612,12 @@ , packetType = 21 , .. }+ GetVersion{} ->+ Header+ { size = headerSize+ , packetType = 32+ , ..+ } GetColor{} -> Header { size = headerSize@@ -571,9 +646,11 @@ putMessagePayload :: Message r -> Put putMessagePayload = \case GetService -> mempty+ GetHostFirmware -> mempty GetPower -> mempty SetPower b -> putWord16le if b then maxBound else minBound+ GetVersion -> mempty GetColor -> mempty SetColor HSBK{..} d -> do putWord8 0@@ -585,6 +662,112 @@ SetLightPower b d -> do putWord16le if b then maxBound else minBound putWord32le $ nominalDiffTimeToInt @Milli d++{- Product info -}++productInfoMap :: Map Word32 (Features, Map Word32 ProductInfo)+productInfoMap =+ Map.fromList $+ productInfo <&> \VendorInfo{..} ->+ ( vid+ ,+ ( defaults+ , Map.fromList $ (pid &&& id) <$> products+ )+ )++-- | Information about a particular LIFX product.+data Product = Product+ { name :: Text+ , productId :: Word32+ , features :: Features+ }+ deriving (Show)++-- | Ask a device for it's vendor and product ID, and look up info on it from the official database.+getProductInfo :: MonadLifx m => Device -> m Product+getProductInfo dev = do+ StateHostFirmware{..} <- sendMessage dev GetHostFirmware+ StateVersion{..} <- sendMessage dev GetVersion+ case productInfoMap !? vendor of+ Nothing -> lifxThrow $ UnknownVendorId vendor+ Just (defaults, products) -> case products !? product of+ Nothing -> lifxThrow $ UnknownProductId product+ Just ProductInfo{features = originalFeatures, ..} ->+ pure+ Product+ { name+ , productId = product+ , features =+ completeFeatures defaults $+ foldl+ ( \old Upgrade{..} ->+ if (versionMajor, versionMinor) >= (major, minor)+ then addFeatures features old+ else old+ )+ originalFeatures+ upgrades+ }+ where+ --TODO RecordDotSyntax+ completeFeatures+ Features+ { ..+ }+ PartialFeatures+ { hev = maybe_hev+ , color = maybe_color+ , chain = maybe_chain+ , matrix = maybe_matrix+ , relays = maybe_relays+ , buttons = maybe_buttons+ , infrared = maybe_infrared+ , multizone = maybe_multizone+ , temperatureRange = maybe_temperatureRange+ , extendedMultizone = maybe_extendedMultizone+ } =+ Features+ { hev = fromMaybe hev maybe_hev+ , color = fromMaybe color maybe_color+ , chain = fromMaybe chain maybe_chain+ , matrix = fromMaybe matrix maybe_matrix+ , relays = fromMaybe relays maybe_relays+ , buttons = fromMaybe buttons maybe_buttons+ , infrared = fromMaybe infrared maybe_infrared+ , multizone = fromMaybe multizone maybe_multizone+ , temperatureRange = maybe_temperatureRange <|> temperatureRange+ , extendedMultizone = fromMaybe extendedMultizone maybe_extendedMultizone+ }+ -- left-biased+ addFeatures+ PartialFeatures+ { ..+ }+ PartialFeatures+ { hev = old_hev+ , color = old_color+ , chain = old_chain+ , matrix = old_matrix+ , relays = old_relays+ , buttons = old_buttons+ , infrared = old_infrared+ , multizone = old_multizone+ , temperatureRange = old_temperatureRange+ , extendedMultizone = old_extendedMultizone+ } =+ PartialFeatures+ { hev = hev <|> old_hev+ , color = color <|> old_color+ , chain = chain <|> old_chain+ , matrix = matrix <|> old_matrix+ , relays = relays <|> old_relays+ , buttons = buttons <|> old_buttons+ , infrared = infrared <|> old_infrared+ , multizone = multizone <|> old_multizone+ , temperatureRange = temperatureRange <|> old_temperatureRange+ , extendedMultizone = extendedMultizone <|> old_extendedMultizone+ } {- Util -}