├── .gitignore ├── Assets ├── Hue.meta └── Hue │ ├── Editor.meta │ ├── Editor │ ├── HueBridgeEditor.cs │ ├── HueBridgeEditor.cs.meta │ ├── HueLampDrawer.cs │ └── HueLampDrawer.cs.meta │ ├── Examples.meta │ ├── Examples │ ├── Prefabs.meta │ ├── Prefabs │ │ ├── LampMenuPrefab.prefab │ │ └── LampMenuPrefab.prefab.meta │ ├── Scenes.meta │ ├── Scenes │ │ ├── Unity Hue Demo.unity │ │ └── Unity Hue Demo.unity.meta │ ├── Scripts.meta │ └── Scripts │ │ ├── HueDemo.cs │ │ ├── HueDemo.cs.meta │ │ ├── HueUIRepresentation.cs │ │ └── HueUIRepresentation.cs.meta │ ├── Scripts.meta │ ├── Scripts │ ├── Helper.meta │ ├── Helper │ │ ├── Data Classes.meta │ │ ├── Data Classes │ │ │ ├── HueBridgeInfo.cs │ │ │ ├── HueBridgeInfo.cs.meta │ │ │ ├── HueKeys.cs │ │ │ ├── HueKeys.cs.meta │ │ │ ├── HueLampState.cs │ │ │ ├── HueLampState.cs.meta │ │ │ ├── StoredHueInfo.cs │ │ │ └── StoredHueInfo.cs.meta │ │ ├── HueErrorInfo.cs │ │ ├── HueErrorInfo.cs.meta │ │ ├── HueInfoStorer.cs │ │ ├── HueInfoStorer.cs.meta │ │ ├── HueParameters.cs │ │ ├── HueParameters.cs.meta │ │ ├── JSON.meta │ │ ├── JSON │ │ │ ├── JsonHelper.cs │ │ │ ├── JsonHelper.cs.meta │ │ │ ├── JsonParameter.cs │ │ │ ├── JsonParameter.cs.meta │ │ │ ├── MiniJSON.cs │ │ │ └── MiniJSON.cs.meta │ │ ├── UnitySingleton.cs │ │ ├── UnitySingleton.cs.meta │ │ ├── UnityWebrequestHelper.cs │ │ └── UnityWebrequestHelper.cs.meta │ ├── HueBridge.cs │ ├── HueBridge.cs.meta │ ├── HueGroup.cs │ ├── HueGroup.cs.meta │ ├── HueLamp.cs │ └── HueLamp.cs.meta │ ├── readme.txt │ └── readme.txt.meta ├── ProjectSettings ├── AudioManager.asset ├── ClusterInputManager.asset ├── DynamicsManager.asset ├── EditorBuildSettings.asset ├── EditorSettings.asset ├── GraphicsSettings.asset ├── InputManager.asset ├── NavMeshAreas.asset ├── NetworkManager.asset ├── Physics2DSettings.asset ├── ProjectSettings.asset ├── ProjectVersion.txt ├── QualitySettings.asset ├── TagManager.asset ├── TimeManager.asset ├── UnityAdsSettings.asset └── UnityConnectSettings.asset ├── README.md ├── UnityHue.unitypackage └── license.txt /.gitignore: -------------------------------------------------------------------------------- 1 | /[Ll]ibrary/ 2 | /[Tt]emp/ 3 | /[Oo]bj/ 4 | /[Bb]uild/ 5 | /[Bb]uilds/ 6 | /Assets/AssetStoreTools* 7 | # Rider IDE files 8 | /.idea/ 9 | 10 | # Autogenerated VS/MD solution and project files 11 | ExportedObj/ 12 | *.csproj 13 | *.unityproj 14 | *.sln 15 | *.suo 16 | *.tmp 17 | *.user 18 | *.userprefs 19 | *.pidb 20 | *.booproj 21 | *.svd 22 | 23 | 24 | # Unity3D generated meta files 25 | *.pidb.meta 26 | 27 | # Unity3D Generated File On Crash Reports 28 | sysinfo.txt 29 | 30 | # Builds 31 | *.apk 32 | -------------------------------------------------------------------------------- /Assets/Hue.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 122e9ecea2269d443b230a3c016cda23 3 | folderAsset: yes 4 | timeCreated: 1439905950 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Hue/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bda179744fb934577986ffc0e663afd7 3 | folderAsset: yes 4 | DefaultImporter: 5 | userData: 6 | -------------------------------------------------------------------------------- /Assets/Hue/Editor/HueBridgeEditor.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | 4 | namespace UnityHue{ 5 | [CustomEditor(typeof(HueBridge), true)] 6 | [CanEditMultipleObjects] 7 | public class HueBridgeEditor : Editor { 8 | 9 | public override void OnInspectorGUI() 10 | { 11 | DrawDefaultInspector(); 12 | HueBridge script = target as HueBridge; 13 | 14 | if(GUILayout.Button("Discover Bridge", GUILayout.Height(30))) 15 | { 16 | script.DiscoverBridges(()=> 17 | { 18 | if(script.Bridges.Count < 1) 19 | Debug.LogWarning("No bridges found in Network"); 20 | }); 21 | } 22 | 23 | GUILayout.Space(7f); 24 | 25 | if(script.CurrentBridge == null || string.IsNullOrEmpty(script.CurrentBridge.ip)) 26 | { 27 | EditorGUILayout.HelpBox("The current bridge doesn't have an ip", MessageType.Warning); 28 | } 29 | else 30 | { 31 | if(GUILayout.Button("Get Lights", GUILayout.Height(30))) 32 | { 33 | script.UpdateLights(); 34 | } 35 | 36 | GUILayout.Space(7f); 37 | 38 | if(GUILayout.Button("Get Groups", GUILayout.Height(30))) 39 | { 40 | script.UpdateGroups(); 41 | } 42 | 43 | GUILayout.Space(7f); 44 | 45 | if(string.IsNullOrEmpty(script.CurrentBridge.applicationName) || string.IsNullOrEmpty(script.CurrentBridge.deviceName)) 46 | { 47 | EditorGUILayout.HelpBox("The current bridge doesn't have application name and device name", MessageType.Warning); 48 | }else 49 | { 50 | if(string.IsNullOrEmpty(script.CurrentBridge.applicationName)) 51 | { 52 | EditorGUILayout.HelpBox("Their is already a username that will be overwritten if you create a new user", MessageType.Info); 53 | GUILayout.Space(7f); 54 | } 55 | if(GUILayout.Button("Create User", GUILayout.Height(30))) 56 | script.CreateUser(); 57 | } 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Assets/Hue/Editor/HueBridgeEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 164a7c002e18b46fa9f273f4c8c120d9 3 | timeCreated: 1474874457 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Hue/Editor/HueLampDrawer.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | using System; 4 | using System.Linq; 5 | using System.Collections; 6 | using System.Collections.Generic; 7 | using System.Reflection; 8 | 9 | namespace UnityHue{ 10 | [CustomPropertyDrawer(typeof(HueLamp))] 11 | public class HueLampDrawer : PropertyDrawer { 12 | 13 | 14 | public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) 15 | { 16 | EditorGUI.PropertyField(position, property, label, true); 17 | if (property.isExpanded) 18 | { 19 | 20 | if (GUI.Button(new Rect(position.xMin + 30f, position.yMax - 20f, position.width - 30f, 20f), "Set State")) 21 | { 22 | string id = property.FindPropertyRelative("id").stringValue; 23 | //pretty ugly but 24 | HueLamp lamp = HueBridge.instance.Lights.Find(x => x.id == id); 25 | if(lamp != null) 26 | lamp.SetState(); 27 | } 28 | } 29 | } 30 | 31 | public override float GetPropertyHeight(SerializedProperty property, GUIContent label) 32 | { 33 | if (property.isExpanded) 34 | return EditorGUI.GetPropertyHeight(property) + 20f; 35 | return EditorGUI.GetPropertyHeight(property); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Assets/Hue/Editor/HueLampDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e0105e5c50b2240538c73254aed385ac 3 | timeCreated: 1474905670 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Hue/Examples.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2a95d799f29994e9aa2fa7492f00c9cf 3 | folderAsset: yes 4 | timeCreated: 1474960991 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Hue/Examples/Prefabs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 667a98d88fbf54f629f9e9c4a7427532 3 | folderAsset: yes 4 | DefaultImporter: 5 | userData: 6 | -------------------------------------------------------------------------------- /Assets/Hue/Examples/Prefabs/LampMenuPrefab.prefab: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-bbr/UnityHue/4c69097b5ecbc75428b6f8977a5e79b730f74c0b/Assets/Hue/Examples/Prefabs/LampMenuPrefab.prefab -------------------------------------------------------------------------------- /Assets/Hue/Examples/Prefabs/LampMenuPrefab.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2383a1cb40b9f4554ba0c183ebf49d9b 3 | timeCreated: 1474965891 4 | licenseType: Free 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Hue/Examples/Scenes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ead09fda330edb24f80834fdab2eaf45 3 | folderAsset: yes 4 | timeCreated: 1439909909 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Hue/Examples/Scenes/Unity Hue Demo.unity: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-bbr/UnityHue/4c69097b5ecbc75428b6f8977a5e79b730f74c0b/Assets/Hue/Examples/Scenes/Unity Hue Demo.unity -------------------------------------------------------------------------------- /Assets/Hue/Examples/Scenes/Unity Hue Demo.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: de022211b8f5c5d4597104dfe654389c 3 | timeCreated: 1439909955 4 | licenseType: Pro 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Hue/Examples/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: df0470bc00d60419ba9c972cdf9e0e74 3 | folderAsset: yes 4 | timeCreated: 1474961031 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Hue/Examples/Scripts/HueDemo.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.UI; 3 | using System.Collections; 4 | using UnityHue; 5 | 6 | namespace UnityHue.Examples{ 7 | public class HueDemo : MonoBehaviour { 8 | public HueInfoStorer storer; 9 | public GameObject hueUIRepresentationPrefab; 10 | public GameObject createUserScreen; 11 | public Text createUserText; 12 | public Button createUserButton; 13 | public RectTransform lampMenu; 14 | public string applicationName = "UHue", deviceName ="MyHue"; 15 | 16 | 17 | void Awake () { 18 | //Either the ip and username are stored in the monobehaviour or it was succesfully restored from player prefs 19 | if((HueBridge.instance.CurrentBridge != null && HueBridge.instance.CurrentBridge.HasIP && HueBridge.instance.CurrentBridge.HasUsername)|| 20 | storer.Restore()) 21 | { 22 | HueBridge.instance.UpdateLights(OnLightsRetrieved, HandleLightsError); 23 | }else 24 | { 25 | //We have to discover the bridges 26 | HueBridge.instance.DiscoverBridges(OnBridgesDiscovered); 27 | } 28 | } 29 | public void OnLightsRetrieved() 30 | { 31 | createUserScreen.SetActive(false); 32 | foreach(var lamp in HueBridge.instance.Lights) 33 | { 34 | GameObject representation = Instantiate(hueUIRepresentationPrefab, lampMenu) as GameObject; 35 | representation.GetComponent().Initialize(lamp); 36 | } 37 | storer.Save(); 38 | } 39 | public void OnBridgesDiscovered() 40 | { 41 | createUserScreen.SetActive(true); 42 | if(HueBridge.instance.Bridges.Count < 1) 43 | { 44 | createUserText.text = "Couldn't find any bridges in your Network"; 45 | createUserButton.gameObject.SetActive(false); 46 | Debug.LogWarning("Failed to find Bridges in your Network"); 47 | }else 48 | createUserButton.gameObject.SetActive(true); 49 | 50 | } 51 | public void RegisterApp() 52 | { 53 | HueBridge.instance.CreateUser(applicationName, deviceName, ()=> HueBridge.instance.UpdateLights(OnLightsRetrieved), OnRegistrationError); 54 | createUserButton.gameObject.SetActive(false); 55 | } 56 | public void HandleLightsError(HueErrorInfo error) 57 | { 58 | Debug.LogWarning(error); 59 | if(!error.IsRequestError) 60 | return; 61 | Debug.Log( "Connecting to a previously stored hue failed, trying to discover new bridges"); 62 | HueBridge.instance.DiscoverBridges(OnBridgesDiscovered); 63 | } 64 | 65 | public void OnRegistrationError(HueErrorInfo error) 66 | { 67 | if(error.errorCode == 101) 68 | { 69 | createUserText.text = "The Link Button on the Bridge wasn't pressed. Press it and try again"; 70 | createUserButton.gameObject.SetActive(true); 71 | }else 72 | HueErrorInfo.LogError(error); 73 | 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /Assets/Hue/Examples/Scripts/HueDemo.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cef35e91e823341d7ad833d0332c0583 3 | timeCreated: 1474961556 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Hue/Examples/Scripts/HueUIRepresentation.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.UI; 3 | using System.Collections; 4 | using UnityHue; 5 | 6 | namespace UnityHue.Examples{ 7 | public class HueUIRepresentation : MonoBehaviour { 8 | private HueLamp lamp; 9 | public Text nameText; 10 | public Toggle onToggle; 11 | public Slider hueSlider; 12 | public Slider brightnessSlider; 13 | public Slider saturationSlider; 14 | public Slider transitionTime; 15 | private bool effectActive; 16 | 17 | public void Initialize(HueLamp lamp) 18 | { 19 | this.lamp = lamp; 20 | nameText.text = lamp.name; 21 | } 22 | 23 | public void SetState() 24 | { 25 | if(lamp == null) 26 | return; 27 | lamp.SetState( 28 | HueParameters.LightOnParameter(onToggle.isOn), 29 | HueParameters.BrightnessParameter((int) brightnessSlider.value), 30 | HueParameters.HueParameter((int) hueSlider.value), 31 | HueParameters.SaturationParameter((int) saturationSlider.value), 32 | HueParameters.TransitionParameter((int) transitionTime.value) 33 | ); 34 | } 35 | public void SetColorLoop() 36 | { 37 | if(lamp == null) 38 | return; 39 | effectActive = !effectActive; 40 | lamp.SetState( 41 | HueParameters.EffectParameter(effectActive ? "colorloop" : "none") 42 | ); 43 | } 44 | public void SetBlink() 45 | { 46 | if(lamp == null) 47 | return; 48 | lamp.SetState( 49 | HueParameters.AlertParameter() 50 | ); 51 | } 52 | public void SetRacingColors(float timeOut = 1f) 53 | { 54 | if(lamp == null) 55 | return; 56 | StartCoroutine(RacingCountdown(timeOut)); 57 | } 58 | IEnumerator RacingCountdown(float timeOut = 1f) 59 | { 60 | //Change the color instantly (no transition time) 61 | lamp.SetColor(Color.red, HueParameters.TransitionParameter(0)); 62 | yield return new WaitForSeconds(timeOut); 63 | lamp.SetColor(Color.yellow, HueParameters.TransitionParameter(0)); 64 | yield return new WaitForSeconds(timeOut); 65 | lamp.SetColor(Color.green,HueParameters.TransitionParameter(0)); 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /Assets/Hue/Examples/Scripts/HueUIRepresentation.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4a45276bed95c41f6969df717b33b9f7 3 | timeCreated: 1474964330 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d12bb7c7c493a456f894afd0e77e5da0 3 | folderAsset: yes 4 | DefaultImporter: 5 | userData: 6 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: de388a8560bb046e4bfcc366631c1fc6 3 | folderAsset: yes 4 | timeCreated: 1474889042 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/Data Classes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b3d4d064aa8e1491aabec60f74f345e6 3 | folderAsset: yes 4 | timeCreated: 1474961741 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/Data Classes/HueBridgeInfo.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace UnityHue { 3 | [System.Serializable] 4 | public class HueBridgeInfo { 5 | public string id; 6 | public string name; 7 | public string ip; 8 | public string macAdress; 9 | public string userName; 10 | public string applicationName; 11 | public string deviceName; 12 | 13 | public HueBridgeInfo (string id, string name, string ip, string macAdress) 14 | { 15 | this.id = id; 16 | this.name = name; 17 | this.ip = ip; 18 | this.macAdress = macAdress; 19 | } 20 | public HueBridgeInfo (string id, string ip) 21 | { 22 | this.id = id; 23 | this.ip = ip; 24 | } 25 | public HueBridgeInfo () 26 | { 27 | 28 | } 29 | 30 | public bool HasIP { 31 | get { 32 | return !string.IsNullOrEmpty(ip); 33 | } 34 | } 35 | public bool HasUsername { 36 | get { 37 | return !string.IsNullOrEmpty(userName); 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/Data Classes/HueBridgeInfo.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 22dd66d5fe0d84c468f86c055b013f1f 3 | timeCreated: 1474871576 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/Data Classes/HueKeys.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace UnityHue{ 3 | /// 4 | /// Class with string keys for the api parameters 5 | /// 6 | public class HueKeys { 7 | public const string ON = "on"; 8 | public const string BRIGHTNESS = "bri"; 9 | public const string HUE = "hue"; 10 | public const string SATURATION = "sat"; 11 | public const string ALERT = "alert"; 12 | public const string EFFECT = "effect"; 13 | public const string STATE = "state"; 14 | public const string COLOR_MODE = "colormode"; 15 | public const string NAME = "name"; 16 | public const string REACHABLE = "reachable"; 17 | public const string TYPE = "type"; 18 | public const string MODEL_ID = "modelid"; 19 | public const string SOFTWARE_VERSION = "swversion"; 20 | public const string TRANSITION = "transitiontime"; 21 | public const string COLOR_LOOP = "colorloop"; 22 | public const string SELECT = "select"; 23 | public const string LSELECT = "lselect"; 24 | public const string NONE = "none"; 25 | public const string USER_NAME = "username"; 26 | public const string DEVICE_TYPE = "devicetype"; 27 | public const string ERROR = "error"; 28 | public const string DESCRIPTION = "description"; 29 | public const string ADDRESS = "address"; 30 | public const string LIGHTS = "lights"; 31 | } 32 | } -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/Data Classes/HueKeys.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6473ee16cec754d04be6f66b214bce19 3 | timeCreated: 1474886927 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/Data Classes/HueLampState.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | namespace UnityHue{ 5 | [System.Serializable] 6 | public class HueLampState{ 7 | public bool on = false; 8 | public int brightness; 9 | public int hue; 10 | public int saturation; 11 | [Tooltip("The options are none, select for a short flash, " + 12 | "and lselect for a 15 second flash")] 13 | public string alert; 14 | [Tooltip("The options are none, and colorloop" + 15 | "which cycles through the hue range at " + 16 | "current brightness and saturation")] 17 | public string effect; 18 | public string colorMode; 19 | [Tooltip("The time it takes, in multiples" + 20 | "of 100 ms to reach the new state" + 21 | "from the current state")] 22 | public int transitionTime = 4; 23 | public bool reachable = false; 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/Data Classes/HueLampState.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 18f6f0bb0158b4e63b6c5395c15f2f20 3 | timeCreated: 1474884723 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/Data Classes/StoredHueInfo.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace UnityHue{ 6 | [System.Serializable] 7 | public class StoredHueInfo{ 8 | public HueBridgeInfo current; 9 | public List allBridges; 10 | 11 | public StoredHueInfo (HueBridgeInfo current, List allBridges) 12 | { 13 | this.current = current; 14 | this.allBridges = allBridges; 15 | } 16 | 17 | } 18 | } -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/Data Classes/StoredHueInfo.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: af0f64235ac6c4c9494923c371c44293 3 | timeCreated: 1474959347 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/HueErrorInfo.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using MiniJSON; 6 | 7 | namespace UnityHue{ 8 | /// 9 | /// Stores information about the error that occured when performing an operation 10 | /// with Unity Hue. Can either be an error with the webrequest (webrequest error field) 11 | /// with the hue api (errorcode, address, description) or with unexpected json (failingJson) 12 | /// 13 | [System.Serializable] 14 | public class HueErrorInfo{ 15 | public string webrequestError; 16 | /// 17 | /// The error code, in case this was a hue api error. A list with error codes can be 18 | /// found here: http://www.developers.meethue.com/documentation/error-messages 19 | /// 20 | public int errorCode; 21 | public string address; 22 | public string description; 23 | public string failingJson; 24 | 25 | public HueErrorInfo (string webrequestError, string failingJson = null) 26 | { 27 | this.webrequestError = webrequestError; 28 | this.failingJson = failingJson; 29 | } 30 | 31 | public HueErrorInfo (System.Object jsonObject) 32 | { 33 | var errorObject = JsonHelper.UnravelJson(jsonObject, "error"); 34 | var dict = errorObject as Dictionary; 35 | 36 | if(dict != null) 37 | { 38 | if(dict.ContainsKey(HueKeys.TYPE)) 39 | this.errorCode = int.Parse(dict[HueKeys.TYPE].ToString()); 40 | if(dict.ContainsKey(HueKeys.ADDRESS)) 41 | this.address = dict[HueKeys.ADDRESS].ToString(); 42 | if(dict.ContainsKey(HueKeys.DESCRIPTION)) 43 | this.description = dict[HueKeys.DESCRIPTION].ToString(); 44 | } 45 | } 46 | /// 47 | /// Standard way of handling the error. Simply logs all 48 | /// error information to the console 49 | /// 50 | /// Error. 51 | public static void LogError(HueErrorInfo error) 52 | { 53 | Debug.LogWarning(error.ToString()); 54 | } 55 | public override string ToString () 56 | { 57 | var builder = new StringBuilder(); 58 | builder.AppendLine("Unity Hue encountered an error with the following details: "). 59 | AppendLine("Webrequest Error : " + webrequestError). 60 | AppendLine("Error Code : " + errorCode.ToString()). 61 | AppendLine("Adress : " + address). 62 | AppendLine("Description : " + description). 63 | AppendLine("Non-Decoding JSON : " + failingJson); 64 | return builder.ToString(); 65 | } 66 | public static bool JsonContainsErrorKey (System.Object json) 67 | { 68 | return JsonHelper.UnravelJson(json, HueKeys.ERROR) != null; 69 | } 70 | 71 | public bool IsRequestError { 72 | get { 73 | return !string.IsNullOrEmpty(webrequestError); 74 | } 75 | } 76 | public bool IsJsonDecodeError { 77 | get { 78 | return !string.IsNullOrEmpty(failingJson); 79 | } 80 | } 81 | public bool IsHueAPIError { 82 | get { 83 | return !string.IsNullOrEmpty(description); 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/HueErrorInfo.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8a9d20067de984fe2b9a4912d82829eb 3 | timeCreated: 1474896578 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/HueInfoStorer.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | namespace UnityHue { 5 | public class HueInfoStorer : MonoBehaviour { 6 | public string prefKey = "StoredHueInformation"; 7 | 8 | public void Save() 9 | { 10 | PlayerPrefs.SetString(prefKey, HueBridge.instance.GetHueStateString()); 11 | } 12 | public bool Restore() 13 | { 14 | var storedState = PlayerPrefs.GetString(prefKey, ""); 15 | if(string.IsNullOrEmpty(storedState)) 16 | return false; 17 | else 18 | { 19 | HueBridge.instance.RestoreHueFromString(storedState); 20 | return true; 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/HueInfoStorer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b2dc76750e00c4ee5834393901f61a79 3 | timeCreated: 1474961949 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/HueParameters.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | namespace UnityHue{ 5 | /// 6 | /// Commonly used parameters for Hue API calls 7 | /// 8 | public static class HueParameters { 9 | 10 | /// 11 | /// Transforms a RGB into color into the corresponding hue, brightness and saturation 12 | /// parameters for the Hue lamp. 13 | /// 14 | /// Color. 15 | /// Hue. 16 | /// Saturation. 17 | /// Brightness. 18 | public static void ColorParameter(Color color, out JsonParameter hue, out JsonParameter saturation, out JsonParameter brightness) 19 | { 20 | Vector3 hsv = HueLamp.HueHSVfromRGB(color); 21 | hue = HueParameter(Mathf.RoundToInt(hsv.x)); 22 | saturation = SaturationParameter(Mathf.RoundToInt(hsv.y)); 23 | brightness = BrightnessParameter(Mathf.RoundToInt(hsv.z)); 24 | } 25 | 26 | public static JsonParameter LightOnParameter(bool on) 27 | { 28 | return new JsonParameter(HueKeys.ON, on); 29 | } 30 | public static JsonParameter BrightnessParameter(int brightness) 31 | { 32 | return new JsonParameter(HueKeys.BRIGHTNESS, brightness); 33 | } 34 | public static JsonParameter HueParameter(int hue) 35 | { 36 | return new JsonParameter(HueKeys.HUE, hue); 37 | } 38 | public static JsonParameter SaturationParameter(int sat) 39 | { 40 | return new JsonParameter(HueKeys.SATURATION, sat); 41 | } 42 | /// 43 | /// Creates a transitiontime parameter. This sets the duration of the transition 44 | /// between the current and the new state as a multiple of 100 ms so the default 45 | /// transitionTime of 4 results in a 400ms transition 46 | /// 47 | /// The parameter. 48 | /// Transition time. 49 | public static JsonParameter TransitionParameter(int transitionTime = 4) 50 | { 51 | return new JsonParameter(HueKeys.TRANSITION, transitionTime); 52 | } 53 | /// 54 | /// Creates an effect parameter. Options currently are "none" and "colorloop" cycling 55 | /// through the hue range with current brightness and saturation 56 | /// 57 | /// The parameter. 58 | /// Alert type. 59 | public static JsonParameter EffectParameter(string effectType = HueKeys.COLOR_LOOP) 60 | { 61 | return new JsonParameter(HueKeys.EFFECT, effectType); 62 | } 63 | /// 64 | /// Creates an alert parameter. Options currently are "none", "select" performing one 65 | /// breath cycle and "lselect" performing breath cycles for 15 seconds 66 | /// 67 | /// The parameter. 68 | /// Alert type. 69 | public static JsonParameter AlertParameter(string alertType = HueKeys.SELECT) 70 | { 71 | return new JsonParameter(HueKeys.ALERT, alertType); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/HueParameters.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 21fd3b7fb448b415e92765222bda3c6a 3 | timeCreated: 1475055195 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/JSON.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d95d224ddc6624f07a8e2928b34cf457 3 | folderAsset: yes 4 | timeCreated: 1474840814 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/JSON/JsonHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using MiniJSON; 4 | 5 | namespace UnityHue { 6 | public static class JsonHelper { 7 | //finds the first occurence of an object in a dictionary with a supplied key 8 | //a bit ugly but gets the job done quick most of the time 9 | public static System.Object UnravelJson(System.Object obj, string keyToLookFor) 10 | { 11 | if(obj is List) 12 | { 13 | var list = obj as List; 14 | foreach(var item in list) 15 | { 16 | var result = UnravelJson(item, keyToLookFor); 17 | if(result != null) 18 | return result; 19 | } 20 | return null; 21 | }else if(obj is Dictionary) 22 | { 23 | return RecurseThroughDictionary(obj as Dictionary, keyToLookFor); 24 | }else 25 | return null; 26 | } 27 | public static System.Object RecurseThroughDictionary (Dictionary dict, string keyToLookFor) 28 | { 29 | if(dict.ContainsKey(keyToLookFor)) 30 | return dict[keyToLookFor]; 31 | 32 | foreach(var entry in dict) 33 | { 34 | var result = UnravelJson(entry.Value, keyToLookFor); 35 | if(result != null) 36 | return result; 37 | } 38 | return null; 39 | } 40 | public static void RecurseThroughDictionary (Dictionary dict, string keyToLookFor, 41 | ref List results) 42 | { 43 | if(dict.ContainsKey(keyToLookFor)) 44 | results.Add(dict[keyToLookFor]); 45 | 46 | foreach(var entry in dict) 47 | { 48 | UnravelJson(entry.Value, keyToLookFor, ref results); 49 | } 50 | } 51 | /// 52 | /// Gets a list of all the objects with the supplied keys somewhere in the json 53 | /// 54 | /// Object. 55 | /// Key to look for. 56 | /// Results. 57 | public static void UnravelJson(System.Object obj, string keyToLookFor, ref List results) 58 | { 59 | if(obj is List) 60 | { 61 | var list = obj as List; 62 | foreach(var item in list) 63 | { 64 | UnravelJson(item, keyToLookFor, ref results); 65 | } 66 | }else if(obj is Dictionary) 67 | { 68 | RecurseThroughDictionary(obj as Dictionary, keyToLookFor); 69 | } 70 | } 71 | 72 | public static Dictionary CreateJsonParameterDictionary(params JsonParameter[] parameters) 73 | { 74 | var dict = new Dictionary(); 75 | foreach(var parameter in parameters) 76 | { 77 | dict.Add(parameter.parameterKey, parameter.parameterValue); 78 | } 79 | return dict; 80 | } 81 | public static string CreateJsonParameterString(params JsonParameter[] parameters) 82 | { 83 | return Json.Serialize(CreateJsonParameterDictionary(parameters)); 84 | } 85 | 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/JSON/JsonHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 35527564976594a39a69a0d6eae72f15 3 | timeCreated: 1474840843 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/JSON/JsonParameter.cs: -------------------------------------------------------------------------------- 1 | namespace UnityHue{ 2 | /// 3 | /// A struct with a key and an object value. One or more JsonParameter 4 | /// can then be used to constructe a Json dictionary with the helper 5 | /// functions in JsonHelper. Has constructors that automatically box 6 | /// common types (bool, int, float, string) into an object 7 | /// 8 | public struct JsonParameter { 9 | public string parameterKey; 10 | public System.Object parameterValue; 11 | 12 | 13 | public JsonParameter (string parameterKey, System.Object parameterValue) 14 | { 15 | this.parameterKey = parameterKey; 16 | this.parameterValue = parameterValue; 17 | } 18 | public JsonParameter (string parameterKey, bool parameterValue) 19 | { 20 | this.parameterKey = parameterKey; 21 | this.parameterValue = parameterValue as System.Object; 22 | } 23 | public JsonParameter (string parameterKey, float parameterValue) 24 | { 25 | this.parameterKey = parameterKey; 26 | this.parameterValue = parameterValue as System.Object; 27 | } 28 | public JsonParameter (string parameterKey, int parameterValue) 29 | { 30 | this.parameterKey = parameterKey; 31 | this.parameterValue = parameterValue as System.Object; 32 | } 33 | public JsonParameter (string parameterKey, string parameterValue) 34 | { 35 | this.parameterKey = parameterKey; 36 | this.parameterValue = parameterValue as System.Object; 37 | } 38 | public JsonParameter (string parameterKey, params JsonParameter[] parameterValue) 39 | { 40 | this.parameterKey = parameterKey; 41 | this.parameterValue = JsonHelper.CreateJsonParameterDictionary(parameterValue) as System.Object; 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/JSON/JsonParameter.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a06591a1f46954f9d8449f2a106a111a 3 | timeCreated: 1475047416 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/JSON/MiniJSON.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Calvin Rien 3 | * 4 | * Based on the JSON parser by Patrick van Bergen 5 | * http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html 6 | * 7 | * Simplified it so that it doesn't throw exceptions 8 | * and can be used in Unity iPhone with maximum code stripping. 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining 11 | * a copy of this software and associated documentation files (the 12 | * "Software"), to deal in the Software without restriction, including 13 | * without limitation the rights to use, copy, modify, merge, publish, 14 | * distribute, sublicense, and/or sell copies of the Software, and to 15 | * permit persons to whom the Software is furnished to do so, subject to 16 | * the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 25 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 26 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 27 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | */ 29 | using System; 30 | using System.Collections; 31 | using System.Collections.Generic; 32 | using System.IO; 33 | using System.Text; 34 | 35 | namespace MiniJSON { 36 | // Example usage: 37 | // 38 | // using UnityEngine; 39 | // using System.Collections; 40 | // using System.Collections.Generic; 41 | // using MiniJSON; 42 | // 43 | // public class MiniJSONTest : MonoBehaviour { 44 | // void Start () { 45 | // var jsonString = "{ \"array\": [1.44,2,3], " + 46 | // "\"object\": {\"key1\":\"value1\", \"key2\":256}, " + 47 | // "\"string\": \"The quick brown fox \\\"jumps\\\" over the lazy dog \", " + 48 | // "\"unicode\": \"\\u3041 Men\u00fa sesi\u00f3n\", " + 49 | // "\"int\": 65536, " + 50 | // "\"float\": 3.1415926, " + 51 | // "\"bool\": true, " + 52 | // "\"null\": null }"; 53 | // 54 | // var dict = Json.Deserialize(jsonString) as Dictionary; 55 | // 56 | // Debug.Log("deserialized: " + dict.GetType()); 57 | // Debug.Log("dict['array'][0]: " + ((List) dict["array"])[0]); 58 | // Debug.Log("dict['string']: " + (string) dict["string"]); 59 | // Debug.Log("dict['float']: " + (double) dict["float"]); // floats come out as doubles 60 | // Debug.Log("dict['int']: " + (long) dict["int"]); // ints come out as longs 61 | // Debug.Log("dict['unicode']: " + (string) dict["unicode"]); 62 | // 63 | // var str = Json.Serialize(dict); 64 | // 65 | // Debug.Log("serialized: " + str); 66 | // } 67 | // } 68 | 69 | /// 70 | /// This class encodes and decodes JSON strings. 71 | /// Spec. details, see http://www.json.org/ 72 | /// 73 | /// JSON uses Arrays and Objects. These correspond here to the datatypes IList and IDictionary. 74 | /// All numbers are parsed to doubles. 75 | /// 76 | public static class Json { 77 | /// 78 | /// Parses the string json into a value 79 | /// 80 | /// A JSON string. 81 | /// An List<object>, a Dictionary<string, object>, a double, an integer,a string, null, true, or false 82 | public static object Deserialize(string json) { 83 | // save the string for debug information 84 | if (json == null) { 85 | return null; 86 | } 87 | 88 | return Parser.Parse(json); 89 | } 90 | 91 | sealed class Parser : IDisposable { 92 | const string WORD_BREAK = "{}[],:\""; 93 | 94 | public static bool IsWordBreak(char c) { 95 | return Char.IsWhiteSpace(c) || WORD_BREAK.IndexOf(c) != -1; 96 | } 97 | 98 | enum TOKEN { 99 | NONE, 100 | CURLY_OPEN, 101 | CURLY_CLOSE, 102 | SQUARED_OPEN, 103 | SQUARED_CLOSE, 104 | COLON, 105 | COMMA, 106 | STRING, 107 | NUMBER, 108 | TRUE, 109 | FALSE, 110 | NULL 111 | }; 112 | 113 | StringReader json; 114 | 115 | Parser(string jsonString) { 116 | json = new StringReader(jsonString); 117 | } 118 | 119 | public static object Parse(string jsonString) { 120 | using (var instance = new Parser(jsonString)) { 121 | return instance.ParseValue(); 122 | } 123 | } 124 | 125 | public void Dispose() { 126 | json.Dispose(); 127 | json = null; 128 | } 129 | 130 | Dictionary ParseObject() { 131 | Dictionary table = new Dictionary(); 132 | 133 | // ditch opening brace 134 | json.Read(); 135 | 136 | // { 137 | while (true) { 138 | switch (NextToken) { 139 | case TOKEN.NONE: 140 | return null; 141 | case TOKEN.COMMA: 142 | continue; 143 | case TOKEN.CURLY_CLOSE: 144 | return table; 145 | default: 146 | // name 147 | string name = ParseString(); 148 | if (name == null) { 149 | return null; 150 | } 151 | 152 | // : 153 | if (NextToken != TOKEN.COLON) { 154 | return null; 155 | } 156 | // ditch the colon 157 | json.Read(); 158 | 159 | // value 160 | table[name] = ParseValue(); 161 | break; 162 | } 163 | } 164 | } 165 | 166 | List ParseArray() { 167 | List array = new List(); 168 | 169 | // ditch opening bracket 170 | json.Read(); 171 | 172 | // [ 173 | var parsing = true; 174 | while (parsing) { 175 | TOKEN nextToken = NextToken; 176 | 177 | switch (nextToken) { 178 | case TOKEN.NONE: 179 | return null; 180 | case TOKEN.COMMA: 181 | continue; 182 | case TOKEN.SQUARED_CLOSE: 183 | parsing = false; 184 | break; 185 | default: 186 | object value = ParseByToken(nextToken); 187 | 188 | array.Add(value); 189 | break; 190 | } 191 | } 192 | 193 | return array; 194 | } 195 | 196 | object ParseValue() { 197 | TOKEN nextToken = NextToken; 198 | return ParseByToken(nextToken); 199 | } 200 | 201 | object ParseByToken(TOKEN token) { 202 | switch (token) { 203 | case TOKEN.STRING: 204 | return ParseString(); 205 | case TOKEN.NUMBER: 206 | return ParseNumber(); 207 | case TOKEN.CURLY_OPEN: 208 | return ParseObject(); 209 | case TOKEN.SQUARED_OPEN: 210 | return ParseArray(); 211 | case TOKEN.TRUE: 212 | return true; 213 | case TOKEN.FALSE: 214 | return false; 215 | case TOKEN.NULL: 216 | return null; 217 | default: 218 | return null; 219 | } 220 | } 221 | 222 | string ParseString() { 223 | StringBuilder s = new StringBuilder(); 224 | char c; 225 | 226 | // ditch opening quote 227 | json.Read(); 228 | 229 | bool parsing = true; 230 | while (parsing) { 231 | 232 | if (json.Peek() == -1) { 233 | parsing = false; 234 | break; 235 | } 236 | 237 | c = NextChar; 238 | switch (c) { 239 | case '"': 240 | parsing = false; 241 | break; 242 | case '\\': 243 | if (json.Peek() == -1) { 244 | parsing = false; 245 | break; 246 | } 247 | 248 | c = NextChar; 249 | switch (c) { 250 | case '"': 251 | case '\\': 252 | case '/': 253 | s.Append(c); 254 | break; 255 | case 'b': 256 | s.Append('\b'); 257 | break; 258 | case 'f': 259 | s.Append('\f'); 260 | break; 261 | case 'n': 262 | s.Append('\n'); 263 | break; 264 | case 'r': 265 | s.Append('\r'); 266 | break; 267 | case 't': 268 | s.Append('\t'); 269 | break; 270 | case 'u': 271 | var hex = new char[4]; 272 | 273 | for (int i=0; i< 4; i++) { 274 | hex[i] = NextChar; 275 | } 276 | 277 | s.Append((char) Convert.ToInt32(new string(hex), 16)); 278 | break; 279 | } 280 | break; 281 | default: 282 | s.Append(c); 283 | break; 284 | } 285 | } 286 | 287 | return s.ToString(); 288 | } 289 | 290 | object ParseNumber() { 291 | string number = NextWord; 292 | 293 | if (number.IndexOf('.') == -1) { 294 | long parsedInt; 295 | Int64.TryParse(number, out parsedInt); 296 | return parsedInt; 297 | } 298 | 299 | double parsedDouble; 300 | Double.TryParse(number, out parsedDouble); 301 | return parsedDouble; 302 | } 303 | 304 | void EatWhitespace() { 305 | while (Char.IsWhiteSpace(PeekChar)) { 306 | json.Read(); 307 | 308 | if (json.Peek() == -1) { 309 | break; 310 | } 311 | } 312 | } 313 | 314 | char PeekChar { 315 | get { 316 | return Convert.ToChar(json.Peek()); 317 | } 318 | } 319 | 320 | char NextChar { 321 | get { 322 | return Convert.ToChar(json.Read()); 323 | } 324 | } 325 | 326 | string NextWord { 327 | get { 328 | StringBuilder word = new StringBuilder(); 329 | 330 | while (!IsWordBreak(PeekChar)) { 331 | word.Append(NextChar); 332 | 333 | if (json.Peek() == -1) { 334 | break; 335 | } 336 | } 337 | 338 | return word.ToString(); 339 | } 340 | } 341 | 342 | TOKEN NextToken { 343 | get { 344 | EatWhitespace(); 345 | 346 | if (json.Peek() == -1) { 347 | return TOKEN.NONE; 348 | } 349 | 350 | switch (PeekChar) { 351 | case '{': 352 | return TOKEN.CURLY_OPEN; 353 | case '}': 354 | json.Read(); 355 | return TOKEN.CURLY_CLOSE; 356 | case '[': 357 | return TOKEN.SQUARED_OPEN; 358 | case ']': 359 | json.Read(); 360 | return TOKEN.SQUARED_CLOSE; 361 | case ',': 362 | json.Read(); 363 | return TOKEN.COMMA; 364 | case '"': 365 | return TOKEN.STRING; 366 | case ':': 367 | return TOKEN.COLON; 368 | case '0': 369 | case '1': 370 | case '2': 371 | case '3': 372 | case '4': 373 | case '5': 374 | case '6': 375 | case '7': 376 | case '8': 377 | case '9': 378 | case '-': 379 | return TOKEN.NUMBER; 380 | } 381 | 382 | switch (NextWord) { 383 | case "false": 384 | return TOKEN.FALSE; 385 | case "true": 386 | return TOKEN.TRUE; 387 | case "null": 388 | return TOKEN.NULL; 389 | } 390 | 391 | return TOKEN.NONE; 392 | } 393 | } 394 | } 395 | 396 | /// 397 | /// Converts a IDictionary / IList object or a simple type (string, int, etc.) into a JSON string 398 | /// 399 | /// A Dictionary<string, object> / List<object> 400 | /// A JSON encoded string, or null if object 'json' is not serializable 401 | public static string Serialize(object obj) { 402 | return Serializer.Serialize(obj); 403 | } 404 | 405 | sealed class Serializer { 406 | StringBuilder builder; 407 | 408 | Serializer() { 409 | builder = new StringBuilder(); 410 | } 411 | 412 | public static string Serialize(object obj) { 413 | var instance = new Serializer(); 414 | 415 | instance.SerializeValue(obj); 416 | 417 | return instance.builder.ToString(); 418 | } 419 | 420 | void SerializeValue(object value) { 421 | IList asList; 422 | IDictionary asDict; 423 | string asStr; 424 | 425 | if (value == null) { 426 | builder.Append("null"); 427 | } else if ((asStr = value as string) != null) { 428 | SerializeString(asStr); 429 | } else if (value is bool) { 430 | builder.Append((bool) value ? "true" : "false"); 431 | } else if ((asList = value as IList) != null) { 432 | SerializeArray(asList); 433 | } else if ((asDict = value as IDictionary) != null) { 434 | SerializeObject(asDict); 435 | } else if (value is char) { 436 | SerializeString(new string((char) value, 1)); 437 | } else { 438 | SerializeOther(value); 439 | } 440 | } 441 | 442 | void SerializeObject(IDictionary obj) { 443 | bool first = true; 444 | 445 | builder.Append('{'); 446 | 447 | foreach (object e in obj.Keys) { 448 | if (!first) { 449 | builder.Append(','); 450 | } 451 | 452 | SerializeString(e.ToString()); 453 | builder.Append(':'); 454 | 455 | SerializeValue(obj[e]); 456 | 457 | first = false; 458 | } 459 | 460 | builder.Append('}'); 461 | } 462 | 463 | void SerializeArray(IList anArray) { 464 | builder.Append('['); 465 | 466 | bool first = true; 467 | 468 | foreach (object obj in anArray) { 469 | if (!first) { 470 | builder.Append(','); 471 | } 472 | 473 | SerializeValue(obj); 474 | 475 | first = false; 476 | } 477 | 478 | builder.Append(']'); 479 | } 480 | 481 | void SerializeString(string str) { 482 | builder.Append('\"'); 483 | 484 | char[] charArray = str.ToCharArray(); 485 | foreach (var c in charArray) { 486 | switch (c) { 487 | case '"': 488 | builder.Append("\\\""); 489 | break; 490 | case '\\': 491 | builder.Append("\\\\"); 492 | break; 493 | case '\b': 494 | builder.Append("\\b"); 495 | break; 496 | case '\f': 497 | builder.Append("\\f"); 498 | break; 499 | case '\n': 500 | builder.Append("\\n"); 501 | break; 502 | case '\r': 503 | builder.Append("\\r"); 504 | break; 505 | case '\t': 506 | builder.Append("\\t"); 507 | break; 508 | default: 509 | int codepoint = Convert.ToInt32(c); 510 | if ((codepoint >= 32) && (codepoint <= 126)) { 511 | builder.Append(c); 512 | } else { 513 | builder.Append("\\u"); 514 | builder.Append(codepoint.ToString("x4")); 515 | } 516 | break; 517 | } 518 | } 519 | 520 | builder.Append('\"'); 521 | } 522 | 523 | void SerializeOther(object value) { 524 | // NOTE: decimals lose precision during serialization. 525 | // They always have, I'm just letting you know. 526 | // Previously floats and doubles lost precision too. 527 | if (value is float) { 528 | builder.Append(((float) value).ToString("R")); 529 | } else if (value is int 530 | || value is uint 531 | || value is long 532 | || value is sbyte 533 | || value is byte 534 | || value is short 535 | || value is ushort 536 | || value is ulong) { 537 | builder.Append(value); 538 | } else if (value is double 539 | || value is decimal) { 540 | builder.Append(Convert.ToDouble(value).ToString("R")); 541 | } else { 542 | SerializeString(value.ToString()); 543 | } 544 | } 545 | } 546 | } 547 | } 548 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/JSON/MiniJSON.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f20927dad1bcd42cf9ced8e927b6cb6b 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/UnitySingleton.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | namespace UnityHue{ 5 | /// 6 | /// Unity singleton. A Monobehaviour variant of the Singleton Pattern 7 | /// 8 | public abstract class UnitySingleton : MonoBehaviour where T : MonoBehaviour{ 9 | 10 | 11 | private static T _instance = null; 12 | 13 | /// 14 | /// Gets the instance or instantiates an instance on a new Gameobject 15 | /// 16 | /// The instance. 17 | public static T instance { 18 | 19 | get { 20 | if (_instance == null) { 21 | _instance = GameObject.FindObjectOfType(typeof(T)) as T; 22 | if (_instance == null) { 23 | _instance = new GameObject().AddComponent(); 24 | _instance.gameObject.name = _instance.GetType().Name; 25 | } 26 | } 27 | return _instance; 28 | 29 | } 30 | 31 | } 32 | public static bool HasInstance { 33 | get { 34 | return !IsDestroyed; 35 | } 36 | } 37 | 38 | public static bool IsDestroyed { 39 | get { 40 | return (_instance == null) ? true : false; 41 | } 42 | } 43 | 44 | protected virtual void OnDestroy () { 45 | onDestruction(); 46 | _instance = null; 47 | } 48 | 49 | protected void OnApplicationQuit () { 50 | onDestruction(); 51 | _instance = null; 52 | } 53 | protected virtual void onDestruction() 54 | { 55 | StopAllCoroutines(); 56 | } 57 | 58 | } 59 | } -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/UnitySingleton.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e4a6ac783cb4c4a1c9b1aec52ec75363 3 | timeCreated: 1438601360 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/UnityWebrequestHelper.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.Networking; 3 | using System.Collections; 4 | 5 | public static class UnityWebrequestHelper { 6 | 7 | /// 8 | /// Non URL encoded post request for a json submit. 9 | /// 10 | /// The URL encoded post request. 11 | /// URL. 12 | /// Post data. 13 | public static UnityWebRequest NonURLEncodedPost(string url, string postData) 14 | { 15 | var request = new UnityWebRequest(url, "POST"); 16 | byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(postData); 17 | request.uploadHandler = new UploadHandlerRaw(bodyRaw) as UploadHandler; 18 | request.downloadHandler = new DownloadHandlerBuffer() as DownloadHandler; 19 | request.SetRequestHeader("Content-Type", "application/json"); 20 | return request; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/Helper/UnityWebrequestHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ad9a2d43df4784c6da4c475327102e3e 3 | timeCreated: 1474840936 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/HueBridge.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.Networking; 3 | using System; 4 | using System.Collections; 5 | using System.Collections.Generic; 6 | 7 | using MiniJSON; 8 | 9 | namespace UnityHue{ 10 | /// 11 | /// Singleton that interfaces with the Hue API. Generally the HueBridge Component 12 | /// doesn't have to be present in a scene but can bootstrap itself 13 | /// 14 | [AddComponentMenu("Unity Hue/Hue Bridge")] 15 | public class HueBridge : UnitySingleton { 16 | [Tooltip("Used for discovery of all the bridges in your network" + 17 | " (that have contacted a philipps server in the past.)")] 18 | [SerializeField] 19 | private string hueDiscoveryServer = "https://www.meethue.com/api/nupnp"; 20 | [SerializeField] 21 | private HueBridgeInfo currentBridge; 22 | [SerializeField] 23 | protected List lamps = new List(); 24 | [SerializeField] 25 | protected List groups = new List(); 26 | public List Bridges { get; private set;} 27 | 28 | void Awake () 29 | { 30 | DontDestroyOnLoad(this); 31 | } 32 | #region Public Functions 33 | 34 | /// 35 | /// Start discovery of bridges in the current network 36 | /// OnFinished will be called after a sucessful response 37 | /// (even if the response is that zero bridges are in the network). 38 | /// If there are more than zero bridges in the Network the first one 39 | /// will be assigned to currentBridge, the full list is accesible under 40 | /// the Bridges property. 41 | /// 42 | /// On finished. 43 | public void DiscoverBridges(Action onFinished = null) 44 | { 45 | DiscoverBridges(onFinished, HueErrorInfo.LogError); 46 | } 47 | public void DiscoverBridges(Action onFinished, Action errorCallback) 48 | { 49 | StartCoroutine(GetBridgesEnumerator( 50 | x => { 51 | Bridges = x; 52 | if(Bridges.Count > 0) 53 | currentBridge = Bridges[0]; 54 | if(onFinished != null) 55 | onFinished(); 56 | }, 57 | errorCallback)); 58 | } 59 | 60 | public void UpdateLights(Action onFinished = null) 61 | { 62 | UpdateLights(onFinished, HueErrorInfo.LogError); 63 | } 64 | public void UpdateLights(Action onFinished, Action errorCallback) 65 | { 66 | DiscoverLights(x => { 67 | lamps = x; 68 | if(onFinished != null) 69 | onFinished(); 70 | }, errorCallback); 71 | } 72 | public void UpdateGroups(Action onFinished = null) 73 | { 74 | UpdateGroups(onFinished, HueErrorInfo.LogError); 75 | } 76 | public void UpdateGroups(Action onFinished, Action errorCallback) 77 | { 78 | DiscoverGroups(x => { 79 | groups = x; 80 | if(onFinished != null) 81 | onFinished(); 82 | }, errorCallback); 83 | } 84 | public void DiscoverLights(Action> lampsCallback, Action errorCallback) 85 | { 86 | StartCoroutine(DiscoverLightsEnumerator(lampsCallback, errorCallback)); 87 | } 88 | public void DiscoverGroups(Action> groupsCallBack, Action errorCallback) 89 | { 90 | StartCoroutine(DiscoverGroupsEnumerator(groupsCallBack, errorCallback)); 91 | } 92 | public void CreateUser(Action onFinished = null, Action errorCallback = null) 93 | { 94 | CreateUser((x) => { 95 | currentBridge.userName = x; 96 | if(onFinished != null) 97 | onFinished(); 98 | }, errorCallback); 99 | } 100 | public void CreateUser(string applicationName, string deviceName, Action onFinished = null, Action errorCallback = null) 101 | { 102 | CreateUser(applicationName, deviceName, 103 | (x) => { 104 | currentBridge.userName = x; 105 | if(onFinished != null) 106 | onFinished(); 107 | }, errorCallback); 108 | } 109 | public void CreateUser(Action generatedUsername, Action errorCallback) 110 | { 111 | CreateUser(currentBridge.applicationName, currentBridge.deviceName, generatedUsername, errorCallback); 112 | } 113 | public void CreateUser(string applicationName, string deviceName, Action generatedUsername, 114 | Action errorCallback) 115 | { 116 | StartCoroutine(CreateUserEnumerator(applicationName, deviceName, generatedUsername, errorCallback)); 117 | } 118 | 119 | /// 120 | /// Deletes the lamp, careful with this one 121 | /// 122 | /// Lamp name. 123 | /// Success callback. 124 | /// Error callback. 125 | public void DeleteLamp(string id, Action errorCallback = null) 126 | { 127 | StartCoroutine(DeleteLampEnumerator(id, errorCallback)); 128 | } 129 | /// 130 | /// Deletes a group, careful with this one 131 | /// 132 | /// Lamp name. 133 | /// Success callback. 134 | /// Error callback. 135 | public void DeleteGroup(string id, Action errorCallback = null) 136 | { 137 | StartCoroutine(DeleteGroupEnumerator(id, errorCallback)); 138 | } 139 | public void UpdateLamp(string id, HueLamp lampToUpdate, Action errorCallback = null) 140 | { 141 | StartCoroutine(UpdateLampEnumerator(id, lampToUpdate, errorCallback)); 142 | } 143 | public string GetHueStateString() 144 | { 145 | return JsonUtility.ToJson(GetStorableHueState()); 146 | } 147 | public void RestoreHueFromString(string jsonContent) 148 | { 149 | if(string.IsNullOrEmpty(jsonContent)) 150 | return; 151 | RestoreHueState(JsonUtility.FromJson(jsonContent)); 152 | } 153 | public StoredHueInfo GetStorableHueState() 154 | { 155 | return new StoredHueInfo(currentBridge, Bridges); 156 | } 157 | public void RestoreHueState( StoredHueInfo savedState) 158 | { 159 | if(savedState == null) 160 | return; 161 | Bridges = savedState.allBridges; 162 | currentBridge = savedState.current; 163 | } 164 | 165 | #endregion 166 | 167 | #region Private Functions 168 | 169 | void ProcessBridges(string jsonResponse, Action> ipCallback) 170 | { 171 | var list = new List(); 172 | var response = Json.Deserialize(jsonResponse); 173 | if(response is List) 174 | { 175 | var responseList = response as List; 176 | foreach(var item in responseList) 177 | { 178 | if(!(item is Dictionary)) 179 | continue; 180 | var dict = item as Dictionary; 181 | var bridgeInfo = new HueBridgeInfo(dict["id"].ToString(), dict["internalipaddress"].ToString()); 182 | if(dict.ContainsKey("macaddress")) 183 | bridgeInfo.macAdress = dict["macaddress"].ToString(); 184 | if(dict.ContainsKey("name")) 185 | bridgeInfo.name = dict["name"].ToString(); 186 | list.Add(bridgeInfo); 187 | } 188 | } 189 | ipCallback(list); 190 | } 191 | 192 | void ProcessLights (string jsonResponse, Action> lampsCallback, Action errorCallback) 193 | { 194 | var response = Json.Deserialize(jsonResponse); 195 | if(HueErrorInfo.JsonContainsErrorKey(response)) 196 | { 197 | if(errorCallback != null) 198 | errorCallback(new HueErrorInfo(response)); 199 | return; 200 | } 201 | if(!(response is Dictionary)) 202 | { 203 | if(errorCallback != null) 204 | errorCallback(new HueErrorInfo(null, jsonResponse)); 205 | return; 206 | } 207 | var dict = response as Dictionary; 208 | var list = new List(); 209 | foreach(var kv in dict) 210 | { 211 | string id = kv.Key; 212 | if(!(kv.Value is Dictionary)) 213 | continue; 214 | var lightDict = kv.Value as Dictionary; 215 | var lamp = new HueLamp(id); 216 | ProcessLampUpdate(lightDict, lamp); 217 | list.Add(lamp); 218 | } 219 | lampsCallback(list); 220 | } 221 | void ProcessGroups (string jsonResponse, Action> groupCallBack, Action errorCallback) 222 | { 223 | var response = Json.Deserialize(jsonResponse); 224 | if(HueErrorInfo.JsonContainsErrorKey(response)) 225 | { 226 | if(errorCallback != null) 227 | errorCallback(new HueErrorInfo(response)); 228 | return; 229 | } 230 | if(!(response is Dictionary)) 231 | { 232 | if(errorCallback != null) 233 | errorCallback(new HueErrorInfo(null, jsonResponse)); 234 | return; 235 | } 236 | var dict = response as Dictionary; 237 | var list = new List(); 238 | foreach(var kv in dict) 239 | { 240 | string id = kv.Key; 241 | if(!(kv.Value is Dictionary)) 242 | continue; 243 | var groupDict = kv.Value as Dictionary; 244 | string name = groupDict[HueKeys.NAME].ToString(); 245 | var group = new HueGroup(name, id); 246 | list.Add(group); 247 | } 248 | groupCallBack(list); 249 | } 250 | 251 | void ProcessLampUpdate(string jsonResponse, HueLamp lampToUpdate, Action errorCallback) 252 | { 253 | var response = Json.Deserialize(jsonResponse); 254 | if(HueErrorInfo.JsonContainsErrorKey(response)) 255 | { 256 | if(errorCallback != null) 257 | errorCallback(new HueErrorInfo(response)); 258 | return; 259 | } 260 | if(!(response is Dictionary)) 261 | { 262 | if(errorCallback != null) 263 | errorCallback(new HueErrorInfo(null, jsonResponse)); 264 | return; 265 | } 266 | var dict = response as Dictionary; 267 | ProcessLampUpdate(dict, lampToUpdate); 268 | } 269 | void ProcessLampUpdate(Dictionary dict, HueLamp lampToUpdate) 270 | { 271 | lampToUpdate.name = dict[HueKeys.NAME].ToString(); 272 | lampToUpdate.modelID = dict[HueKeys.MODEL_ID].ToString(); 273 | lampToUpdate.type = dict[HueKeys.TYPE].ToString(); 274 | lampToUpdate.softwareVersion = dict[HueKeys.SOFTWARE_VERSION].ToString(); 275 | var stateDict = dict[HueKeys.STATE] as Dictionary; 276 | lampToUpdate.lampState = GetStateFromDictionary(stateDict); 277 | } 278 | 279 | #endregion 280 | 281 | #region Request Enumerators 282 | 283 | IEnumerator GetBridgesEnumerator(Action> ipCallback, Action errorCallback = null) 284 | { 285 | UnityWebRequest bridgesWebRequest = UnityWebRequest.Get(hueDiscoveryServer); 286 | yield return bridgesWebRequest.Send(); 287 | 288 | if(bridgesWebRequest.isError) 289 | { 290 | if(errorCallback != null) 291 | errorCallback(new HueErrorInfo(bridgesWebRequest.error, null)); 292 | } 293 | else { 294 | ProcessBridges(bridgesWebRequest.downloadHandler.text, ipCallback); 295 | } 296 | } 297 | 298 | IEnumerator CreateUserEnumerator(string applicationName, string deviceName, 299 | Action generatedUserName, Action errorCallback = null) 300 | { 301 | string json = JsonHelper.CreateJsonParameterString( 302 | new JsonParameter(HueKeys.DEVICE_TYPE, applicationName + "#" + deviceName) 303 | ); 304 | //Unity Webrequest making this more difficult than it should be 305 | var createUserRequest = UnityWebrequestHelper.NonURLEncodedPost(BaseURL, json); 306 | yield return createUserRequest.Send(); 307 | 308 | if(createUserRequest.isError) 309 | { 310 | if(errorCallback != null) 311 | errorCallback(new HueErrorInfo(createUserRequest.error, null)); 312 | } 313 | else { 314 | var response = Json.Deserialize(createUserRequest.downloadHandler.text); 315 | if(HueErrorInfo.JsonContainsErrorKey(response)) 316 | { 317 | if(errorCallback != null) 318 | errorCallback(new HueErrorInfo(response)); 319 | 320 | }else 321 | { 322 | var userName = JsonHelper.UnravelJson(response, HueKeys.USER_NAME); 323 | if(userName != null) 324 | generatedUserName(userName.ToString()); 325 | } 326 | } 327 | } 328 | 329 | IEnumerator DeleteLampEnumerator (string id, Action errorCallback = null) 330 | { 331 | string url = BaseURLWithUserName + "/lights/" + id; 332 | UnityWebRequest deleteRequest = UnityWebRequest.Delete(url); 333 | yield return deleteRequest.Send(); 334 | if(deleteRequest.isError && errorCallback != null) 335 | errorCallback(new HueErrorInfo(deleteRequest.error, null)); 336 | } 337 | IEnumerator DeleteGroupEnumerator (string id, Action errorCallback = null) 338 | { 339 | string url = BaseURLWithUserName + "/groups/" + id; 340 | UnityWebRequest deleteRequest = UnityWebRequest.Delete(url); 341 | yield return deleteRequest.Send(); 342 | if(deleteRequest.isError && errorCallback != null) 343 | errorCallback(new HueErrorInfo(deleteRequest.error, null)); 344 | } 345 | 346 | IEnumerator UpdateLampEnumerator (string id, HueLamp lampToUpdate, 347 | Action errorCallback = null) 348 | { 349 | string url = BaseURLWithUserName + "/lights/" + id; 350 | UnityWebRequest stateRequest = UnityWebRequest.Get(url); 351 | yield return stateRequest.Send(); 352 | if(stateRequest.isError) 353 | { 354 | if(errorCallback != null) 355 | errorCallback(new HueErrorInfo(stateRequest.error, null)); 356 | }else 357 | { 358 | ProcessLampUpdate(stateRequest.downloadHandler.text, lampToUpdate, errorCallback); 359 | } 360 | } 361 | 362 | IEnumerator DiscoverLightsEnumerator(Action> lampsCallback, Action errorCallback) { 363 | UnityWebRequest lightsRequest = UnityWebRequest.Get(BaseURL+"/"+currentBridge.userName+"/lights"); 364 | yield return lightsRequest.Send(); 365 | 366 | if(lightsRequest.isError) 367 | { 368 | if(errorCallback != null) 369 | errorCallback(new HueErrorInfo(lightsRequest.error, null)); 370 | } 371 | else { 372 | ProcessLights(lightsRequest.downloadHandler.text, lampsCallback, errorCallback); 373 | } 374 | } 375 | IEnumerator DiscoverGroupsEnumerator(Action> groups, Action errorCallback) { 376 | UnityWebRequest groupsRequest = UnityWebRequest.Get(BaseURL+"/"+currentBridge.userName+"/groups"); 377 | yield return groupsRequest.Send(); 378 | 379 | if(groupsRequest.isError) 380 | { 381 | if(errorCallback != null) 382 | errorCallback(new HueErrorInfo(groupsRequest.error, null)); 383 | } 384 | else { 385 | ProcessGroups(groupsRequest.downloadHandler.text, groups, errorCallback); 386 | } 387 | } 388 | 389 | IEnumerator SendRequestEnumerator(UnityWebRequest request, Action successCallback, 390 | Action errorCallback = null) 391 | { 392 | yield return request.Send(); 393 | 394 | if(request.isError) 395 | { 396 | if(errorCallback != null) 397 | errorCallback(new HueErrorInfo(request.error, null)); 398 | } 399 | else { 400 | if(successCallback != null) 401 | successCallback(request.downloadHandler.text); 402 | } 403 | } 404 | 405 | #endregion 406 | 407 | #region Helper 408 | 409 | public string BaseURL{ 410 | get { 411 | return "http://" + currentBridge.ip + "/api"; 412 | } 413 | } 414 | public string BaseURLWithUserName{ 415 | get { 416 | return "http://" + currentBridge.ip + "/api/"+currentBridge.userName; 417 | } 418 | } 419 | public List Lights { 420 | get { 421 | return lamps; 422 | } 423 | } 424 | public List Groups { 425 | get { 426 | return groups; 427 | } 428 | } 429 | public HueBridgeInfo CurrentBridge { 430 | get { 431 | return currentBridge; 432 | } 433 | } 434 | 435 | HueLampState GetStateFromDictionary(Dictionary dict) 436 | { 437 | var state = new HueLampState(); 438 | state.on = (bool)dict[HueKeys.ON]; 439 | state.reachable = (bool)dict[HueKeys.REACHABLE]; 440 | state.hue = int.Parse(dict[HueKeys.HUE].ToString()); 441 | state.brightness = int.Parse(dict[HueKeys.BRIGHTNESS].ToString()); 442 | state.saturation = int.Parse(dict[HueKeys.SATURATION].ToString()); 443 | state.colorMode = dict[HueKeys.COLOR_MODE].ToString(); 444 | state.effect = dict[HueKeys.EFFECT].ToString(); 445 | state.alert = dict[HueKeys.ALERT].ToString(); 446 | return state; 447 | } 448 | 449 | public void SendRequest(UnityWebRequest request, Action successCallback, Action errorCallback = null) 450 | { 451 | StartCoroutine(SendRequestEnumerator(request, successCallback, errorCallback)); 452 | } 453 | 454 | #endregion 455 | } 456 | } -------------------------------------------------------------------------------- /Assets/Hue/Scripts/HueBridge.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 56fdb4012ad1e434da3f2e7a76b5c6cd 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/HueGroup.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.Networking; 3 | using System; 4 | using System.Collections; 5 | using System.Collections.Generic; 6 | 7 | namespace UnityHue{ 8 | [System.Serializable] 9 | public class HueGroup{ 10 | public string name; 11 | public string id; 12 | 13 | public HueGroup (string name, string id) 14 | { 15 | this.name = name; 16 | this.id = id; 17 | } 18 | 19 | public void SetState (params JsonParameter[] parameters) 20 | { 21 | SetState(null, null, parameters); 22 | } 23 | 24 | public void SetName(string newGroupName, Action successCallback = null, 25 | Action errorCallback = null) 26 | { 27 | ModifyGroup(successCallback, errorCallback, newGroupName); 28 | } 29 | public void SetLights(Action successCallback, 30 | Action errorCallback, params HueLamp[] lamps) 31 | { 32 | ModifyGroup(successCallback, errorCallback, null, lamps); 33 | } 34 | 35 | /// 36 | /// Modifies the group name and lights array both at once 37 | /// If you just want to modify one property set newGroupName 38 | /// to null or don't supply any hue lamps (See SetName or SetLights) 39 | /// 40 | /// Success callback. 41 | /// Error callback. 42 | /// New group name. 43 | /// Lamps. 44 | public void ModifyGroup (Action successCallback, Action errorCallback, 45 | string newGroupName = null, params HueLamp[] lamps) 46 | { 47 | string url = HueBridge.instance.BaseURLWithUserName + "/groups/" + id; 48 | var list = new List(); 49 | foreach(var item in lamps) 50 | { 51 | list.Add(item.id); 52 | } 53 | List parameters = new List(); 54 | if(!string.IsNullOrEmpty(newGroupName)) 55 | { 56 | parameters.Add(new JsonParameter(HueKeys.NAME, newGroupName)); 57 | } 58 | if(list.Count > 0) 59 | { 60 | parameters.Add(new JsonParameter(HueKeys.NAME, list as System.Object)); 61 | } 62 | UnityWebRequest modifyRequest = UnityWebRequest.Put(url, 63 | JsonHelper.CreateJsonParameterString(parameters.ToArray())); 64 | HueBridge.instance.SendRequest(modifyRequest, successCallback, errorCallback); 65 | } 66 | 67 | public void SetState (Action successCallback, 68 | Action errorCallback, params JsonParameter[] parameters) 69 | { 70 | string url = HueBridge.instance.BaseURLWithUserName + "/groups/" + id + "/action"; 71 | UnityWebRequest stateRequest = UnityWebRequest.Put(url, JsonHelper.CreateJsonParameterString(parameters)); 72 | HueBridge.instance.SendRequest(stateRequest, successCallback, errorCallback); 73 | } 74 | /// 75 | /// Deletes the group. 76 | /// 77 | public void Delete() 78 | { 79 | HueBridge.instance.DeleteGroup(id, HueErrorInfo.LogError); 80 | } 81 | public static void CreateHueGroup(Action succesCallback, Action errorCallback, 82 | string groupName, params HueLamp[] lamps) 83 | { 84 | var list = new List(); 85 | foreach(var item in lamps) 86 | { 87 | list.Add(item.id); 88 | } 89 | CreateHueGroup(succesCallback, errorCallback, groupName, list); 90 | } 91 | public static void CreateHueGroup(Action sucessCallback, Action errorCallback, 92 | string groupName, List ids) 93 | { 94 | string url = HueBridge.instance.BaseURLWithUserName + "/groups"; 95 | UnityWebRequest stateRequest = UnityWebrequestHelper.NonURLEncodedPost(url, 96 | JsonHelper.CreateJsonParameterString( 97 | new JsonParameter(HueKeys.NAME, groupName), 98 | new JsonParameter(HueKeys.LIGHTS, ids as System.Object) 99 | )); 100 | HueBridge.instance.SendRequest(stateRequest, sucessCallback, errorCallback); 101 | } 102 | } 103 | } -------------------------------------------------------------------------------- /Assets/Hue/Scripts/HueGroup.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ddfc266cf1387446c8ad779329f64cd9 3 | timeCreated: 1474890235 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/HueLamp.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.Networking; 3 | using System; 4 | using System.Collections; 5 | using System.Collections.Generic; 6 | 7 | using MiniJSON; 8 | 9 | namespace UnityHue{ 10 | /// 11 | /// Class for accessing and modifying a single Hue lamp 12 | /// 13 | [System.Serializable] 14 | public class HueLamp { 15 | public string name; 16 | public string id; 17 | public string type; 18 | public string modelID; 19 | public string softwareVersion; 20 | public HueLampState lampState; 21 | 22 | public HueLamp (string id, string name) 23 | { 24 | this.id = id; 25 | this.name = name; 26 | } 27 | 28 | public HueLamp (string id) 29 | { 30 | this.id = id; 31 | } 32 | 33 | public void SetColor (Color color, params JsonParameter[] additionalParameters) 34 | { 35 | SetColor(color, null, null, additionalParameters); 36 | } 37 | 38 | public void SetColor (Color color, Action successCallback, 39 | Action errorCallback, params JsonParameter[] additionalParameters) 40 | { 41 | JsonParameter hue, bri, sat; 42 | HueParameters.ColorParameter(color, out hue, out sat, out bri); 43 | var list = new List(additionalParameters); 44 | list.Add(hue); 45 | list.Add(bri); 46 | list.Add(sat); 47 | SetState(successCallback, errorCallback, list.ToArray()); 48 | } 49 | 50 | public void UpdateLamp (Action errorCallback = null) 51 | { 52 | HueBridge.instance.UpdateLamp(id, this, errorCallback); 53 | } 54 | 55 | public void SetState () 56 | { 57 | SetState(StateToParameters(this.lampState)); 58 | } 59 | 60 | public void SetState (params JsonParameter[] parameters) 61 | { 62 | SetState(null, null, parameters); 63 | } 64 | 65 | public void SetState (HueLampState state) 66 | { 67 | SetState(null, null, StateToParameters(state)); 68 | } 69 | 70 | public void SetState (HueLampState state, Action successCallback, 71 | Action errorCallback) 72 | { 73 | SetState(successCallback, errorCallback, StateToParameters(state)); 74 | } 75 | /// 76 | /// Sets the state of the lamp according to the supplied JsonParameters 77 | /// A JsonParameter consists of a key (the name of the parameter as specified 78 | /// by the hue api i.e "bri" for brightness) and a value to which that parameter 79 | /// should be set. 80 | /// 81 | /// Success callback. 82 | /// Error callback. 83 | /// Parameters. 84 | public void SetState (Action successCallback, 85 | Action errorCallback, params JsonParameter[] parameters) 86 | { 87 | string url = HueBridge.instance.BaseURLWithUserName + "/lights/" + id + "/state"; 88 | UnityWebRequest stateRequest = UnityWebRequest.Put(url, JsonHelper.CreateJsonParameterString(parameters)); 89 | HueBridge.instance.SendRequest(stateRequest, successCallback, errorCallback); 90 | } 91 | public void SetName (string lampName, Action successCallback = null, Action errorCallback = null) 92 | { 93 | string url = HueBridge.instance.BaseURLWithUserName + "/lights/" + id; 94 | UnityWebRequest renameRequest = UnityWebRequest.Put(url, 95 | JsonHelper.CreateJsonParameterString(new JsonParameter(HueKeys.NAME, lampName))); 96 | HueBridge.instance.SendRequest(renameRequest, successCallback, errorCallback); 97 | } 98 | public static JsonParameter[] StateToParameters(HueLampState state) 99 | { 100 | var list = new List(); 101 | list.Add(new JsonParameter(HueKeys.ON, state.on)); 102 | list.Add(new JsonParameter(HueKeys.BRIGHTNESS, state.brightness)); 103 | list.Add(new JsonParameter(HueKeys.HUE, state.hue)); 104 | list.Add(new JsonParameter(HueKeys.SATURATION, state.saturation)); 105 | list.Add(new JsonParameter(HueKeys.ALERT, state.alert)); 106 | list.Add(new JsonParameter(HueKeys.EFFECT, state.effect)); 107 | list.Add(new JsonParameter(HueKeys.TRANSITION, state.transitionTime)); 108 | return list.ToArray(); 109 | } 110 | 111 | /// 112 | /// Deletes the lamp. 113 | /// 114 | public void Delete() 115 | { 116 | HueBridge.instance.DeleteLamp(id, HueErrorInfo.LogError); 117 | } 118 | 119 | /// 120 | /// Maps an RGB color with (1, 1, 1) being complete white 121 | /// into hue HSV color space with hue going from 0 to 65535, 122 | /// saturation from 0 to 254 and brightness from 1 to 254. 123 | /// Keep in mind that the Hue API only accepts ints for those 124 | /// values. 125 | /// 126 | /// The HS vfrom RG. 127 | /// Rgb. 128 | public static Vector3 HueHSVfromRGB(Color rgb) { 129 | float brightness, hue, saturation; 130 | Color.RGBToHSV(rgb, out hue, out saturation, out brightness); 131 | hue *= 65535f; 132 | saturation *= 254f; 133 | brightness *= 254f; 134 | return new Vector3(hue, saturation, Mathf.Max(brightness, 1f)); 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /Assets/Hue/Scripts/HueLamp.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6cc74dfc72e7a4df294256c0d4be1290 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | -------------------------------------------------------------------------------- /Assets/Hue/readme.txt: -------------------------------------------------------------------------------- 1 | If you want to interact with Hue Lamps (with Unity Hue but also in general) you have to follow the follow steps. 2 | 3 | 1. Find Bridges in your Network (i.e. get their ip adresses) 4 | 2. Authenticate your application with the bridge (i.e pressing the link button on the bridge and requesting authentication within the next 30 seconds) which will give you 5 | a username 6 | 3. Send changes to the bridge with that user name (i.e change brightness on light 3 7 | to value 250 ) 8 | 9 | With Unity Hue you can test out a lot of the functionality in the editor (with the buttons on the Hue Bridge Component) or check out the Unity Hue Demo scene for a runtime example. 10 | So the same steps are: 11 | 12 | 1. 13 | Editor: 14 | Press „Discover Bridge“ on the Hue Bridge Component. It will take a bit to receive a 15 | response but the current bridge field on the Component should now have at least an ip and id (depending on model), or an error will be logged to the console. 16 | Code: 17 | Call one of the overloads (different error and success callbacks options) of HueBridge.instance.DiscoverBridges. The default is to get a list of all bridges and set current bridge to the first element or to log an error if there are no bridges in the network. 18 | 19 | 2. 20 | Editor: 21 | If you have the ip of a bridge, fill in Application Name and Device Name in the current bridge field and press „Create User“. The returned generated user name (if the bridge link was pressed recently) which you can use to authenticate all further requests will become visible in the current bridge field (after a bit) or an error will be logged. It’s useful to store that username for further requests 22 | Code: 23 | Call one of the overloads (different error and success callbacks options again) of HueBridge.instance.CreateUser 24 | 25 | 3. 26 | Now you have all the information (bridge ip and username) you need to interact 27 | with the bridge and change the lamps. You should store this information so you don’t have to repeat steps 1 and 2. The Hue Demo Scene provides an example of that. 28 | 29 | Editor: 30 | Press „Update Lights“ to get a list of the lights connected to your bridge. After a bit the lamps list should be updated and you should see the lamps with their names (i.e living room 1), you can unfold the lamp objects, change their state and press „Set State“ to actually update the lamp 31 | Code: 32 | Call HueBridge.instance.UpdateLights to get a current list of lights, from the on out you can access the list of HueLamp objects with HueBridge.instance.Lights. On the individual HueLamp object you’ll find info such as name, id, type etc. (sometime depending on version) and you can finally set the state of the lamp with lamp.SetState and provide a list of parameters you want changed (see the demo scene and the HueUIRepresentation script for an example). You can also change the name of the lamp, delete it or access a group of lamps at once. 33 | 34 | General Considerations: 35 | Don’t call the api too often. The Philipps API Documentation mentions 10 times a second max for lights and 1 time a second for groups. You can find the Philipps API here (have to sign-up to see it but it’s free): http://www.developers.meethue.com/philips-hue-api 36 | -------------------------------------------------------------------------------- /Assets/Hue/readme.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 07f2190ac9c2142e5ace0d4cc33a80f1 3 | timeCreated: 1474988739 4 | licenseType: Free 5 | TextScriptImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-bbr/UnityHue/4c69097b5ecbc75428b6f8977a5e79b730f74c0b/ProjectSettings/AudioManager.asset -------------------------------------------------------------------------------- /ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-bbr/UnityHue/4c69097b5ecbc75428b6f8977a5e79b730f74c0b/ProjectSettings/ClusterInputManager.asset -------------------------------------------------------------------------------- /ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-bbr/UnityHue/4c69097b5ecbc75428b6f8977a5e79b730f74c0b/ProjectSettings/DynamicsManager.asset -------------------------------------------------------------------------------- /ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-bbr/UnityHue/4c69097b5ecbc75428b6f8977a5e79b730f74c0b/ProjectSettings/EditorBuildSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-bbr/UnityHue/4c69097b5ecbc75428b6f8977a5e79b730f74c0b/ProjectSettings/EditorSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-bbr/UnityHue/4c69097b5ecbc75428b6f8977a5e79b730f74c0b/ProjectSettings/GraphicsSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/InputManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-bbr/UnityHue/4c69097b5ecbc75428b6f8977a5e79b730f74c0b/ProjectSettings/InputManager.asset -------------------------------------------------------------------------------- /ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-bbr/UnityHue/4c69097b5ecbc75428b6f8977a5e79b730f74c0b/ProjectSettings/NavMeshAreas.asset -------------------------------------------------------------------------------- /ProjectSettings/NetworkManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-bbr/UnityHue/4c69097b5ecbc75428b6f8977a5e79b730f74c0b/ProjectSettings/NetworkManager.asset -------------------------------------------------------------------------------- /ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-bbr/UnityHue/4c69097b5ecbc75428b6f8977a5e79b730f74c0b/ProjectSettings/Physics2DSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/ProjectSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-bbr/UnityHue/4c69097b5ecbc75428b6f8977a5e79b730f74c0b/ProjectSettings/ProjectSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 5.6.1f1 2 | -------------------------------------------------------------------------------- /ProjectSettings/QualitySettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-bbr/UnityHue/4c69097b5ecbc75428b6f8977a5e79b730f74c0b/ProjectSettings/QualitySettings.asset -------------------------------------------------------------------------------- /ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-bbr/UnityHue/4c69097b5ecbc75428b6f8977a5e79b730f74c0b/ProjectSettings/TagManager.asset -------------------------------------------------------------------------------- /ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-bbr/UnityHue/4c69097b5ecbc75428b6f8977a5e79b730f74c0b/ProjectSettings/TimeManager.asset -------------------------------------------------------------------------------- /ProjectSettings/UnityAdsSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-bbr/UnityHue/4c69097b5ecbc75428b6f8977a5e79b730f74c0b/ProjectSettings/UnityAdsSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-bbr/UnityHue/4c69097b5ecbc75428b6f8977a5e79b730f74c0b/ProjectSettings/UnityConnectSettings.asset -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UnityHue 2 | Small library that lets you manipulate Philips Hue lamps from within the editor. Uses unity webrequests to communicate with 3 | the hue bridge so it should be pretty crossplatform but will only work in Unity 5.2+ ([More on platform support](https://docs.unity3d.com/Manual/UnityWebRequest.html)). 4 | 5 | ## Functionality: 6 | 7 | - Discover bridges in network 8 | - Authenticate app with bridge (after pressing the link button on the bridge) 9 | - Retrieve list of available lights and light groups 10 | - Rename light, change light state (on/off, color, transition time, alert, effect etc. (pretty much all the api allows)), 11 | get light state and delete light 12 | - Create groups, rename groups and change associated lights, delete groups and change group state (like with lamps but affecting all the lamps in the group) 13 | 14 | ## License: 15 | MIT 16 | -------------------------------------------------------------------------------- /UnityHue.unitypackage: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-bbr/UnityHue/4c69097b5ecbc75428b6f8977a5e79b730f74c0b/UnityHue.unitypackage -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2017 j-bbr 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------------------------------