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!"); } }
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]); } } } } } }
private string GetCurrentInput() { IPremiseObject switcher = GetSwitcherZone(); if (!switcher.IsValidObject()) { return(""); } IPremiseObject currentInput = switcher.GetRefValueAsync("CurrentSource").GetAwaiter().GetResult(); if (!currentInput.IsValidObject()) { return(""); } return(GetInputName(currentInput)); }
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 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); } }); }