Task <IPremiseObject> IPremiseObject.SetClassAsync(IPremiseObject classObject) { var future = new SetClassFuture(_objectId, (classObject as PremiseObject)?._objectId); _client.Send(future, out Task <IPremiseObject> task); return(task); }
Task <IPremiseObject> IPremiseObject.CreateObjectAsync(IPremiseObject type, string name) { var future = new CreateObjectFuture(_objectId, (type as PremiseObject)?._objectId, name); _client.Send(future, out Task <IPremiseObject> task); return(task); }
Task <string> IPremiseObject.GetPropertyAsTextAsync(IPremiseObject property) { var future = new GetPropertyAsTextFuture(_objectId, (property as PremiseObject)?._objectId); _client.Send(future, out Task <string> task); return(task); }
Task <bool> IPremiseObject.IsOfTypeAsync(IPremiseObject typeId) { var future = new IsOfTypeFuture(_objectId, (typeId as PremiseObject)?._objectId); _client.Send(future, out Task <bool> task); return(task); }
public void ProcessControllerDirective() { IPremiseObject switcher = GetSwitcherZone(); if (switcher == null || !switcher.IsValidObject()) { string name = Endpoint.GetPathAsync().GetAwaiter().GetResult(); ReportError(AlexaErrorTypes.NO_SUCH_ENDPOINT, $"No switcher child object in MediaZone at {name}."); return; } Dictionary <string, IPremiseObject> inputs = GetAllInputs(switcher); if (inputs.ContainsKey(Request.directive.payload.input.ToUpper())) { // switch inputs IPremiseObject newInput = inputs[Request.directive.payload.input]; string newInputId = newInput.GetObjectIDAsync().GetAwaiter().GetResult(); switcher.SetValueAsync("CurrentSource", newInputId).GetAwaiter().GetResult(); Response.Event.header.name = "Response"; Response.context.properties.AddRange(PropertyHelpers.FindRelatedProperties(Endpoint, "")); } else { ReportError(AlexaErrorTypes.INVALID_VALUE, $"Input {Request.directive.payload.input} not found!"); } }
public List <AlexaProperty> FindRelatedProperties(IPremiseObject endpoint, string currentController) { List <AlexaProperty> relatedProperties = new List <AlexaProperty>(); DiscoveryEndpoint discoveryEndpoint = PremiseServer.GetDiscoveryEndpointAsync(endpoint).GetAwaiter().GetResult(); if (discoveryEndpoint == null) { return(relatedProperties); } foreach (Capability capability in discoveryEndpoint.capabilities) { if (capability.@interface == currentController) { continue; } if (PremiseServer.Controllers.ContainsKey(capability.@interface)) { IAlexaController controller = PremiseServer.Controllers[capability.@interface]; controller.SetEndpoint(endpoint); relatedProperties.AddRange(controller.GetPropertyStates()); } } return(relatedProperties); }
public static void ShutdownMonitor() { WriteToWindowsApplicationEventLog(EventLogEntryType.Information, "Shutdown monitor started.", 3); while (!BackgroundTaskManager.Shutdown.IsCancellationRequested) { Thread.Sleep(2000); } WriteToWindowsApplicationEventLog(EventLogEntryType.Information, "Shutdown requested by IIS application pool.", 6); UnsubscribeAllAsync().GetAwaiter().GetResult(); _asyncEventSubscription?.UnsubscribeAsync().GetAwaiter().GetResult(); _asyncEventSubscription = null; WriteToWindowsApplicationEventLog(EventLogEntryType.Information, "Removed premise async subscriptions.", 7); using (endpointsLock.Lock()) { endpoints?.Clear(); } WriteToWindowsApplicationEventLog(EventLogEntryType.Information, "Disconnect from premise.", 8); _sysClient.Disconnect(); using (HomeObjectLock.Lock()) { _homeObject = null; } WriteToWindowsApplicationEventLog(EventLogEntryType.Information, "Shutdown complete.", 9); BackgroundTaskManager.Shutdown.ThrowIfCancellationRequested(); }
private string GetInputName(IPremiseObject input) { string inputName = input.GetValueAsync <string>("AlexaInputName").GetAwaiter().GetResult(); if (string.IsNullOrEmpty(inputName)) { // if the AlexaInputName isn't set then use the object name. inputName = input.GetNameAsync().GetAwaiter().GetResult(); } return(inputName.ToUpper()); }
private IPremiseObject GetSwitcherZone() { IPremiseObject switcher = null; foreach (IPremiseObject child in Endpoint.GetChildrenAsync().GetAwaiter().GetResult()) { // there should be an object of type matrix switcher zone as a child if (child.IsOfTypeAsync(PremiseServer.AlexaMatrixSwitcherZone).GetAwaiter().GetResult()) { switcher = child; break; } } return(switcher); }
private static async Task SubscribeAllAsync() { using (subscriptionsLock.Lock()) { if (endpoints.Count == 0) { await GetEndpointsAsync().ConfigureAwait(false); } if (subscriptions.Count != 0) { await UnsubscribeAllAsync().ConfigureAwait(false); } Action <dynamic> callback = AlexaPropertyChanged; using (endpointsLock.Lock()) { foreach (DiscoveryEndpoint discoveryEndpoint in endpoints) { Guid premiseId = new Guid(discoveryEndpoint.endpointId); IPremiseObject endpoint = await HomeObject.GetObjectAsync(premiseId.ToString("B")).ConfigureAwait(false); if (!endpoint.IsValidObject()) { await NotifyErrorAsync(EventLogEntryType.Warning, $"Cannot find object {discoveryEndpoint.friendlyName} ({premiseId.ToString()})to subscribe on premise server.", 250).ConfigureAwait(false); continue; } // use reflection to instantiate all device type controllers var interfaceType = typeof(IAlexaDeviceType); var all = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(x => x.GetTypes()) .Where(x => interfaceType.IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract) .Select(Activator.CreateInstance); foreach (IAlexaDeviceType deviceType in all) { Dictionary <string, IPremiseSubscription> subs = deviceType.SubscribeToSupportedProperties(endpoint, discoveryEndpoint, callback); foreach (string key in subs.Keys) { subscriptions.Add(key, subs[key]); } } } } } }
public List <AlexaProperty> GetPropertyStates(IPremiseObject premiseObject) { Endpoint = premiseObject; List <AlexaProperty> properties = new List <AlexaProperty>(); //double volume = this.endpoint.GetValue<double>(_premiseProperties[0]).GetAwaiter().GetResult(); //AlexaProperty volumeProperty = new AlexaProperty //{ // @namespace = _namespace, // name = _alexaProperties[0], // value = (int)((volume * 100)).LimitToRange(0, 100), // timeOfSample = UtcTimeStamp() //}; //properties.Add(volumeProperty); return(properties); }
private string GetCurrentInput() { IPremiseObject switcher = GetSwitcherZone(); if (!switcher.IsValidObject()) { return(""); } IPremiseObject currentInput = switcher.GetRefValueAsync("CurrentSource").GetAwaiter().GetResult(); if (!currentInput.IsValidObject()) { return(""); } return(GetInputName(currentInput)); }
public static async Task <DiscoveryEndpoint> GetDiscoveryEndpointAsync(IPremiseObject endpoint) { DiscoveryEndpoint discoveryEndpoint; try { string json = await endpoint.GetValueAsync("discoveryJson").ConfigureAwait(false); discoveryEndpoint = JsonConvert.DeserializeObject <DiscoveryEndpoint>(json, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); } catch { discoveryEndpoint = null; } return(discoveryEndpoint); }
private Dictionary <string, IPremiseObject> GetAllInputs(IPremiseObject switcher) { Dictionary <string, IPremiseObject> inputs = new Dictionary <string, IPremiseObject>(); if (switcher == null) { return(inputs); } // The bound object of the switcher should be the output zone object at the device level IPremiseObject boundObject = switcher.GetRefValueAsync("BoundObject").GetAwaiter().GetResult(); if (!boundObject.IsValidObject()) { string path = switcher.GetPathAsync().GetAwaiter().GetResult(); ReportError(AlexaErrorTypes.ENDPOINT_UNREACHABLE, $"No device bound to switcher at {path}."); return(inputs); } // the parent should be the actual switcher IPremiseObject actualSwitcher = boundObject.GetParentAsync().GetAwaiter().GetResult(); if (!actualSwitcher.IsValidObject()) { string path = boundObject.GetPathAsync().GetAwaiter().GetResult(); ReportError(AlexaErrorTypes.INTERNAL_ERROR, $"Unexpected parent at {path}."); return(inputs); } // walk through the children looking for inputs foreach (IPremiseObject child in actualSwitcher.GetChildrenAsync().GetAwaiter().GetResult()) { if (child.IsOfTypeAsync(PremiseServer.AlexaAudioVideoInput).GetAwaiter().GetResult()) { string inputName = GetInputName(child).ToUpper(); inputs.Add(inputName, child); } } return(inputs); }
public AlexaEndpointHealthController(IPremiseObject endpoint) : base(endpoint) { }
public AlexaTemperatureSensor(IPremiseObject endpoint) : base(endpoint) { PropertyHelpers = new AlexaHVAC(); }
public AlexaSpeaker(IPremiseObject endpoint) : base(endpoint) { PropertyHelpers = new AlexaAV(); }
public AlexaSetPowerStateController(IPremiseObject endpoint) : base(endpoint) { PropertyHelpers = new AlexaPower(); }
public AlexaSetSceneController(IPremiseObject endpoint) : base(endpoint) { PropertyHelpers = new AlexaScene(); }
public ControlResponse Control(ControlRequest alexaRequest) { //IPremiseObject PremiseServer.HomeObject, rootObject; var response = new ControlResponse(); #region CheckRequest if ((alexaRequest == null) || (alexaRequest.header == null) || (alexaRequest.header.payloadVersion != "2")) { response.header.@namespace = Faults.Namespace; response.header.name = Faults.UnexpectedInformationReceivedError; response.payload.exception = new ExceptionResponsePayload { faultingParameter = "alexaRequest" }; return(response); } #endregion CheckRequest #region BuildResponse try { response.header.messageId = alexaRequest.header.messageId; response.header.@namespace = alexaRequest.header.@namespace; response.header.name = alexaRequest.header.name.Replace("Request", "Confirmation"); } catch (Exception) { response.header.@namespace = Faults.Namespace; response.header.name = Faults.UnexpectedInformationReceivedError; response.payload.exception = new ExceptionResponsePayload { faultingParameter = "alexaRequest.header.name" }; return(response); } #endregion BuildResponse //SYSClient client = new SYSClient(); #region ConnectToPremise if (PremiseServer.HomeObject == null) { response.header.@namespace = Faults.Namespace; response.header.name = Faults.DependentServiceUnavailableError; response.payload.exception = new ExceptionResponsePayload { dependentServiceName = "Premise Server" }; return(response); } #endregion ConnectToPremise try { if (!CheckAccessToken(alexaRequest.payload.accessToken).GetAwaiter().GetResult()) { response.header.@namespace = Faults.Namespace; response.header.name = Faults.InvalidAccessTokenError; response.payload.exception = new ExceptionResponsePayload(); return(response); } InformLastContact("ControlRequest:" + alexaRequest.payload.appliance.additionalApplianceDetails.path).GetAwaiter().GetResult(); // check request types ControlRequestType requestType = ControlRequestType.Unknown; DeviceType deviceType = DeviceType.Unknown; string command = alexaRequest.header.name.Trim().ToUpper(); switch (command) { case "TURNOFFREQUEST": requestType = ControlRequestType.TurnOffRequest; deviceType = DeviceType.OnOff; break; case "TURNONREQUEST": requestType = ControlRequestType.TurnOnRequest; deviceType = DeviceType.OnOff; break; case "SETTARGETTEMPERATUREREQUEST": requestType = ControlRequestType.SetTargetTemperature; deviceType = DeviceType.Thermostat; break; case "INCREMENTTARGETTEMPERATUREREQUEST": requestType = ControlRequestType.IncrementTargetTemperature; deviceType = DeviceType.Thermostat; break; case "DECREMENTTARGETTEMPERATUREREQUEST": requestType = ControlRequestType.DecrementTargetTemperature; deviceType = DeviceType.Thermostat; break; case "SETPERCENTAGEREQUEST": requestType = ControlRequestType.SetPercentage; deviceType = DeviceType.Dimmer; break; case "INCREMENTPERCENTAGEREQUEST": requestType = ControlRequestType.IncrementPercentage; deviceType = DeviceType.Dimmer; break; case "DECREMENTPERCENTAGEREQUEST": requestType = ControlRequestType.DecrementPercentage; deviceType = DeviceType.Dimmer; break; case "SETCOLORREQUEST": requestType = ControlRequestType.SetColorRequest; deviceType = DeviceType.ColorLight; break; case "SETCOLORTEMPERATUREREQUEST": requestType = ControlRequestType.SetColorTemperatureRequest; deviceType = DeviceType.ColorLight; break; case "INCREMENTCOLORTEMPERATUREREQUEST": requestType = ControlRequestType.IncrementColorTemperature; deviceType = DeviceType.ColorLight; break; case "DECREMENTCOLORTEMPERATUREREQUEST": requestType = ControlRequestType.DecrementColorTemperature; deviceType = DeviceType.ColorLight; break; default: response.header.@namespace = Faults.Namespace; response.header.name = Faults.UnsupportedOperationError; response.payload.exception = new ExceptionResponsePayload(); return(response); } // get the object IPremiseObject applianceToControl = null; try { Guid premiseId = new Guid(alexaRequest.payload.appliance.applianceId); applianceToControl = PremiseServer.RootObject.GetObject(premiseId.ToString("B")).GetAwaiter().GetResult(); if (applianceToControl == null) { throw new Exception(); } } catch { response.header.@namespace = Faults.Namespace; response.header.name = Faults.NoSuchTargetError; response.payload.exception = new ExceptionResponsePayload(); return(response); } if (deviceType == DeviceType.OnOff) { switch (requestType) { case ControlRequestType.TurnOnRequest: applianceToControl.SetValue("PowerState", "True").GetAwaiter().GetResult(); break; case ControlRequestType.TurnOffRequest: applianceToControl.SetValue("PowerState", "False").GetAwaiter().GetResult(); break; default: break; } } else if (deviceType == DeviceType.Dimmer) { double currentValue = 0.0; double adjustValue = 0.0; double valueToSend = 0.0; switch (requestType) { case ControlRequestType.SetPercentage: // obtain the adjustValue adjustValue = Math.Round(double.Parse(alexaRequest.payload.percentageState.value), 2).LimitToRange(0.00, 100.00); // convert from percentage and maintain fractional accuracy valueToSend = Math.Round(adjustValue / 100.00, 4); applianceToControl.SetValue("Brightness", valueToSend.ToString()).GetAwaiter().GetResult(); break; case ControlRequestType.IncrementPercentage: // obtain the adjustValue adjustValue = Math.Round(double.Parse(alexaRequest.payload.deltaPercentage.value) / 100.00, 2).LimitToRange(0.00, 100.00); currentValue = Math.Round(applianceToControl.GetValue <Double>("Brightness").GetAwaiter().GetResult(), 2); // maintain fractional accuracy valueToSend = Math.Round(currentValue + adjustValue, 2).LimitToRange(0.00, 1.00); applianceToControl.SetValue("Brightness", valueToSend.ToString()).GetAwaiter().GetResult(); break; case ControlRequestType.DecrementPercentage: // obtain the adjustValue adjustValue = Math.Round(double.Parse(alexaRequest.payload.deltaPercentage.value) / 100.00, 2).LimitToRange(0.00, 100.00); currentValue = Math.Round(applianceToControl.GetValue <Double>("Brightness").GetAwaiter().GetResult(), 2); // maintain fractional accuracy valueToSend = Math.Round(currentValue - adjustValue, 2).LimitToRange(0.00, 1.00); applianceToControl.SetValue("Brightness", valueToSend.ToString()).GetAwaiter().GetResult(); break; default: break; } } else if (deviceType == DeviceType.ColorLight) { const double adjustValue = 100.0; double currentValue = 0.0; double valueToSend = 0.0; response.payload.achievedState = new AchievedState(); switch (requestType) { case ControlRequestType.SetColorRequest: // obtain the adjustValue double hue = Math.Round(alexaRequest.payload.color.hue.LimitToRange(0, 360), 1); double saturation = Math.Round(alexaRequest.payload.color.saturation, 4); double brightness = Math.Round(alexaRequest.payload.color.brightness, 4); // set the values applianceToControl.SetValue("Hue", hue.ToString()).GetAwaiter().GetResult(); applianceToControl.SetValue("Saturation", saturation.ToString()).GetAwaiter().GetResult(); applianceToControl.SetValue("Brightness", brightness.ToString()).GetAwaiter().GetResult(); // read them back for achieved state response.payload.achievedState.color = new ApplianceColorValue { hue = Math.Round(applianceToControl.GetValue <Double>("Hue").GetAwaiter().GetResult(), 1), saturation = Math.Round(applianceToControl.GetValue <Double>("Saturation").GetAwaiter().GetResult(), 4), brightness = Math.Round(applianceToControl.GetValue <Double>("Brightness").GetAwaiter().GetResult(), 4) }; break; case ControlRequestType.SetColorTemperatureRequest: valueToSend = alexaRequest.payload.colorTemperature.value.LimitToRange(1000, 10000); // set the value applianceToControl.SetValue("Temperature", Math.Round(valueToSend, 0).ToString()).GetAwaiter().GetResult(); // read it back response.payload.achievedState.colorTemperature = new ApplianceColorTemperatureValue { value = applianceToControl.GetValue <int>("Temperature").GetAwaiter().GetResult() }; break; case ControlRequestType.IncrementColorTemperature: currentValue = applianceToControl.GetValue <int>("Temperature").GetAwaiter().GetResult(); valueToSend = Math.Round(currentValue + adjustValue, 0).LimitToRange(1000, 10000); // set the value applianceToControl.SetValue("Temperature", valueToSend.ToString()).GetAwaiter().GetResult(); // read it back response.payload.achievedState.colorTemperature = new ApplianceColorTemperatureValue { value = applianceToControl.GetValue <int>("Temperature").GetAwaiter().GetResult() }; break; case ControlRequestType.DecrementColorTemperature: currentValue = Math.Round(applianceToControl.GetValue <Double>("Temperature").GetAwaiter().GetResult(), 2); valueToSend = Math.Round(currentValue - adjustValue, 0).LimitToRange(1000, 10000); // set the value applianceToControl.SetValue("Temperature", valueToSend.ToString()).GetAwaiter().GetResult(); // read it back response.payload.achievedState.colorTemperature = new ApplianceColorTemperatureValue { value = applianceToControl.GetValue <int>("Temperature").GetAwaiter().GetResult() }; break; default: break; } } else if (deviceType == DeviceType.Thermostat) { int previousTemperatureMode; int temperatureMode; Temperature previousTargetTemperature = null; Temperature targetTemperature = null; double deltaTemperatureC = 0.0; // in C // obtain previous state (sys stores temperatures as K) previousTemperatureMode = applianceToControl.GetValue <int>("TemperatureMode").GetAwaiter().GetResult(); previousTargetTemperature = new Temperature(applianceToControl.GetValue <double>("CurrentSetPoint").GetAwaiter().GetResult()); switch (requestType) { case ControlRequestType.SetTargetTemperature: // get target temperature in C targetTemperature = new Temperature { Celcius = double.Parse(alexaRequest.payload.targetTemperature.value) }; break; case ControlRequestType.IncrementTargetTemperature: // get delta temp in C deltaTemperatureC = double.Parse(alexaRequest.payload.deltaTemperature.value); // increment the targetTemp targetTemperature = new Temperature { Celcius = previousTargetTemperature.Celcius + deltaTemperatureC }; break; case ControlRequestType.DecrementTargetTemperature: // get delta temp in C deltaTemperatureC = double.Parse(alexaRequest.payload.deltaTemperature.value); // decrement the targetTemp targetTemperature = new Temperature { Celcius = previousTargetTemperature.Celcius - deltaTemperatureC }; break; default: targetTemperature = new Temperature(0.00); previousTemperatureMode = 10; // error break; } // set new target temperature applianceToControl.SetValue("CurrentSetPoint", targetTemperature.Kelvin.ToString()).GetAwaiter().GetResult(); response.payload.targetTemperature = new ApplianceValue { value = targetTemperature.Celcius.ToString() }; // get new mode temperatureMode = applianceToControl.GetValue <int>("TemperatureMode").GetAwaiter().GetResult(); // report new mode response.payload.temperatureMode = new ApplianceValue { value = TemperatureMode.ModeToString(temperatureMode) }; // alloc a previousState object response.payload.previousState = new AppliancePreviousState { // report previous mode mode = new ApplianceValue { value = TemperatureMode.ModeToString(previousTemperatureMode) }, // report previous targetTemperature in C targetTemperature = new ApplianceValue { value = previousTargetTemperature.Celcius.ToString() } }; } else { response.header.@namespace = Faults.Namespace; response.header.name = Faults.UnsupportedOperationError; response.payload.exception = new ExceptionResponsePayload(); } } catch { response.header.@namespace = Faults.Namespace; response.header.name = Faults.DriverpublicError; response.payload.exception = new ExceptionResponsePayload(); } return(response); }
public Dictionary <string, IPremiseSubscription> SubscribeToSupportedProperties(IPremiseObject endpoint, DiscoveryEndpoint discoveryEndpoint, Action <dynamic> callback) { Dictionary <string, IPremiseSubscription> subscriptions = new Dictionary <string, IPremiseSubscription>(); foreach (Capability capability in discoveryEndpoint.capabilities) { IPremiseSubscription subscription = null; if (capability.HasProperties() == false) { continue; } if (capability.properties.proactivelyReported) { switch (capability.@interface) { case "Alexa.EndpointHealth": subscription = endpoint.SubscribeAsync("IsReachable", GetType().AssemblyQualifiedName, callback).GetAwaiter().GetResult(); break; } } if (subscription != null) { subscriptions.Add(discoveryEndpoint.endpointId + "." + capability.@interface, subscription); } } return(subscriptions); }
public void SetEndpoint(IPremiseObject premiseObject) { Endpoint = premiseObject; }
public Dictionary <string, IPremiseSubscription> SubscribeToSupportedProperties(IPremiseObject endpoint, DiscoveryEndpoint discoveryEndpoint, Action <dynamic> callback) { Dictionary <string, IPremiseSubscription> subscriptions = new Dictionary <string, IPremiseSubscription>(); foreach (Capability capability in discoveryEndpoint.capabilities) { IPremiseSubscription subscription = null; if (!capability.HasProperties()) // scenes are a special cased { switch (capability.@interface) { case "Alexa.SceneController": subscription = endpoint.SubscribeAsync("PowerState", GetType().AssemblyQualifiedName, callback).GetAwaiter().GetResult(); break; } } if (subscription != null) { subscriptions.Add(discoveryEndpoint.endpointId + "." + capability.@interface, subscription); } } return(subscriptions); }
public AlexaColorTemperatureController(IPremiseObject endpoint) : base(endpoint) { PropertyHelpers = new AlexaLighting(); }
private static bool CheckStatus() { try { if (BackgroundTaskManager.Shutdown.IsCancellationRequested) { return(false); } if (IsClientConnected()) { return(true); } if (_homeObject == null) { using (HomeObjectLock.Lock()) { try { _homeObject = _sysClient.ConnectAsync(PremiseServerAddress)?.GetAwaiter().GetResult(); } catch (Exception ex) { Debug.WriteLine(ex.Message); _homeObject = null; } } if (_homeObject == null) { Debug.WriteLine("Cannot connect to Premise server!"); return(false); } } else { _sysClient.Disconnect(); using (homeObjectSubscriptionLock.Lock()) { _asyncEventSubscription = null; } using (subscriptionsLock.Lock()) { subscriptions.Clear(); _sysClient.Subscriptions.Clear(); } using (endpointsLock.Lock()) { endpoints.Clear(); } using (HomeObjectLock.Lock()) { _homeObject = null; try { _homeObject = _sysClient.ConnectAsync(PremiseServerAddress).GetAwaiter().GetResult(); } catch { _homeObject = null; return(false); } } } using (homeObjectSubscriptionLock.Lock()) { enableAsyncEvents = HomeObject.GetValueAsync <bool>("SendAsyncEventsToAlexa").GetAwaiter().GetResult(); } if (IsAsyncEventsEnabled) { Task.Run(SubscribeAllAsync); } SubScribeToHomeObjectEvents(); return(true); } catch (Exception ex) { _homeObject = null; subscriptions.Clear(); endpoints.Clear(); Debug.WriteLine(ex.Message); return(false); } }
public static void AlexaPropertyChanged(dynamic @params) { Subscription sub = (Subscription)@params; using (deDupeLock.Lock()) { // Premise can send multiple notifications for a single object, one for each // subscribed property that changes. The state report function here will capture // states of all properties, so the DeDupeDictionary prevents multiple state reports // from being sent for essentially the same event. if (DeDupeDictionary.ContainsKey(sub.sysObjectId)) { return; } DeDupeDictionary.Add(sub.sysObjectId, sub); } Task.Run(() => { // get the endpoint and endpoint capabilities Guid premiseId = new Guid(sub.sysObjectId); IPremiseObject endpoint = HomeObject.GetObjectAsync(premiseId.ToString("B")).GetAwaiter().GetResult(); if (!endpoint.IsValidObject()) { return; } DiscoveryEndpoint discoveryEndpoint = GetDiscoveryEndpointAsync(endpoint).GetAwaiter().GetResult(); if (discoveryEndpoint == null) { return; } // get the authorization code for the notification string authCode; using (asyncObjectsLock.Lock()) { authCode = (string)HomeObject.GetValueAsync("AlexaAsyncAuthorizationCode").GetAwaiter().GetResult(); } // build the change report AlexaChangeReport changeReport = new AlexaChangeReport(); [email protected] = Guid.NewGuid().ToString("D"); [email protected].@namespace = "Alexa"; [email protected] = "3"; [email protected] = "BearerToken"; [email protected] = authCode; [email protected] = premiseId.ToString("D").ToUpper(); [email protected] = discoveryEndpoint.cookie; [email protected] = "PHYSICAL_INTERACTION"; // get the device type and controller (e.g. AlexaAV, AlexaHVAC) IAlexaDeviceType deviceType = null; IAlexaController controller = null; List <AlexaProperty> relatedPropertyStates = null; bool hasScene = false; foreach (IAlexaController controllerToTest in Controllers.Values) { if (!controllerToTest.HasPremiseProperty(sub.propertyName)) { continue; } controller = controllerToTest; Type type = Type.GetType(controller.GetAssemblyTypeName()); if (type == null) { continue; } // found a controller, get an instance of the assembly deviceType = (IAlexaDeviceType)Activator.CreateInstance(type); // Determine if this deviceType supports the desired capability // note: This handles situation where the same property name is used by different // controllers. e.g. "brightness" is used in both ColorController and BrightnessController relatedPropertyStates = deviceType.FindRelatedProperties(endpoint, ""); foreach (AlexaProperty property in relatedPropertyStates) { // if so, this is the correct type if (property.@namespace == controller.GetNameSpace()) { break; } } } // ReSharper disable once ConditionIsAlwaysTrueOrFalse if ((deviceType == null) || (controller == null || relatedPropertyStates == null)) { return; } foreach (AlexaProperty prop in relatedPropertyStates) { if (prop.@namespace == "Alexa.SceneController") { hasScene = true; continue; } if (([email protected] == 0) && (prop.name == controller.MapPremisePropertyToAlexaProperty(sub.propertyName))) { [email protected](prop); } else { string propKey = prop.@namespace + "." + prop.name; changeReport.context.propertiesInternal.Add(propKey, prop); } } [email protected] = "ChangeReport"; // scenes are special case if (hasScene) { AlexaSetSceneController sceneController = new AlexaSetSceneController(endpoint); changeReport = sceneController.AlterChangeReport(changeReport); } StateChangeReportWrapper item = new StateChangeReportWrapper { ChangeReport = changeReport }; stateReportQueue.Enqueue(item); using (deDupeLock.Lock()) { DeDupeDictionary.Remove(sub.sysObjectId); } }); }
public AlexaDiscoveryController(IPremiseObject endpoint) : base(endpoint) { }
public AlexaThermostatController(IPremiseObject endpoint) : base(endpoint) { PropertyHelpers = new AlexaHVAC(); }
public AlexaChannelController(IPremiseObject endpoint) : base(endpoint) { PropertyHelpers = new AlexaAV(); }
public Dictionary <string, IPremiseSubscription> SubscribeToSupportedProperties(IPremiseObject endpoint, DiscoveryEndpoint discoveryEndpoint, Action <dynamic> callback) { Dictionary <string, IPremiseSubscription> subscriptions = new Dictionary <string, IPremiseSubscription>(); foreach (Capability capability in discoveryEndpoint.capabilities) { if (capability.HasProperties() == false) { continue; } if (!capability.properties.proactivelyReported) { continue; } IAlexaController controller = null; switch (capability.@interface) { case "Alexa.ChannelController": controller = new AlexaChannelController(); break; case "Alexa.InputController": controller = new AlexaInputController(); break; case "Alexa.PlaybackController": controller = new AlexaPlaybackController(); break; case "Alexa.Speaker": controller = new AlexaSpeaker(); break; } if (controller == null) { continue; } foreach (string premiseProperty in controller.GetPremiseProperties()) { string index = discoveryEndpoint.endpointId + $".{premiseProperty}." + capability.@interface; if (subscriptions.ContainsKey(index)) { continue; } IPremiseSubscription subscription = endpoint.SubscribeAsync(premiseProperty, GetType().AssemblyQualifiedName, callback).GetAwaiter().GetResult(); if (subscription != null) { subscriptions.Add(index, subscription); } } } return(subscriptions); }