Closed TripleNico closed 2 years ago
There's no special call to update a streaming group while it's streaming. If the bridge stops streaming while you update the group, it's best to restart streaming manually.
hi @michielpost thanks for your swift reply. Alright if the bridge stops streaming what would be the "correct" way to recover this? Is that by doing the same steps as noted here: https://github.com/Q42/Q42.HueApi/blob/master/EntertainmentApi.md#connect-to-an-entertainment-group or is there an simpler way?
Yes, safest thing is to follow these steps to setup a new fresh connection.
Calling var entGroup = new StreamingGroup(group.Locations);
needs all light locations. So it's important to have up to date group info when you just added a new light to the group.
Normally, if the connection is lost you might be able to reconnect with this:
client.Close()
await client.Connect(group.Id);
client.AutoUpdate(entGroup, 50);
But creating a new client is safer, that way you're sure all internal state is reset.
Alright i will do some testing to see what the best result is in our case.
Another question, if a light is added to an entertainment group should a location be also set? Or is it just add, re-init streaming and done?
A location is needed for effects that use it. For location aware effects, like a moving light from left to right. If it's not set, the location is probably 0,0, so that might not be what you want.
Today i had some times to dive into this and it seems i'm stuck in a loop. Let me explain:
I setup Entertainment with the code:
//Initialize streaming client
StreamingHueClient client = new StreamingHueClient(ip, key, entertainmentKey);
//Get the entertainment group
var all = await client.LocalHueClient.GetEntertainmentGroups();
var group = all.FirstOrDefault();
//Create a streaming group
var entGroup = new StreamingGroup(group.Locations);
//Connect to the streaming group
await client.Connect(group.Id);
//Start auto updating this entertainment group
client.AutoUpdate(entGroup, 50);
Then if you open the Hue app on your Phone you will see that streaming is active. So far so good.
In the background i have a Task that polls every X seconds to check if HueBridgeConfig.IsStreamingActive
is still active. If not it will try an restore the streaming. For that i tried several options but let's start with this:
//Get the entertainment group
var all = await client.LocalHueClient.GetEntertainmentGroups();
var group = all.FirstOrDefault();
//Create a streaming group
var entGroup = new StreamingGroup(group.Locations);
//Connect to the streaming group
await client.Connect(group.Id);
//Start auto updating this entertainment group
client.AutoUpdate(entGroup, 50);
Now in the Hue app on your Phone click "STOP streaming", the poll task will kick in and fires above code. This results in Streaming Mode being activated again(Yeah!) but after a short time Streaming stops again and i don't know why. Resulting in the poll task kicking in and reconnect, etc.. etc..
I also tried only this single line, with the same result.
var enableResult = await _localHueClient.SetStreamingAsync(groupId);
The only thing i haven't tried yet is also creating a new instance of New StreamingHueClient
but it seams a bit unnecessary to re-active a stopped StreamingGroup...
Any tips?
EDIT 23-07-2021: Added complete test code:
Alright i created a new simple project just to dig down to see what is going wrong. Let me first start with the versions:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net472" />
<package id="Portable.BouncyCastle" version="1.8.10" targetFramework="net472" />
<package id="Q42.HueApi" version="3.18.1" targetFramework="net472" />
<package id="Q42.HueApi.ColorConverters" version="3.18.1" targetFramework="net472" />
<package id="Q42.HueApi.Entertainment" version="3.18.1" targetFramework="net472" />
<package id="System.IO" version="4.3.0" targetFramework="net472" />
<package id="System.Net.Http" version="4.3.4" targetFramework="net472" />
<package id="System.Runtime" version="4.3.0" targetFramework="net472" />
<package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net472" />
<package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net472" />
<package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net472" />
<package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net472" />
</packages>
The project is a WPF app running .NET Framework 4.7.2
The Hue Bridge: ApiVersion = 1.45.0 DataStoreVersion = 107 ModelId = BSB002 SoftwareVersion = 1946080020
The test project is simple and only got one TestButton that initializes everything needed for only the use of EntertainmentAPI. Then it got a Task that act's like a watchdog. I simplyfied this and discoverd that only Client.Connect(Id)
is needed for a restore.
Sorry but the code is in VB.NET but shoudn't be a problem:
Imports System.Threading
Imports Q42.HueApi
Imports Q42.HueApi.ColorConverters
Imports Q42.HueApi.Models.Bridge
Imports Q42.HueApi.Models.Groups
Imports Q42.HueApi.Streaming
Imports Q42.HueApi.Streaming.Extensions
Imports Q42.HueApi.Streaming.Models
Class MainWindow
Private entLayer As EntertainmentLayer
Private Async Sub Button_Click(sender As Object, e As RoutedEventArgs)
'Register app with the bridge
Dim streamClientKey As RegisterEntertainmentResult = Await New LocalHueClient("192.168.70.60").RegisterAsync("MyApp", "MyDevice", True)
'Initialize streaming client
Dim client As New StreamingHueClient(streamClientKey.Ip, streamClientKey.Username, streamClientKey.StreamingClientKey)
'Get the entertainment group
Dim all As IReadOnlyList(Of Group) = Await client.LocalHueClient.GetEntertainmentGroups()
Dim group As Group = all.FirstOrDefault()
'Create a streaming group
Dim entGroup As New StreamingGroup(group.Locations)
'Connect to the streaming group
Await client.Connect(group.Id)
'Start auto updating this entertainment group
Dim SetAndForgetTask As Task = client.AutoUpdate(entGroup, CancellationToken.None, 50)
'Create new base layer
entLayer = entGroup.GetNewLayer(True)
entLayer.SetBrightness(CancellationToken.None, 1)
'Setup Watchdog for streaming with auto recovery
Await Task.Run(Async Function()
Do While True
Dim LocalHueBridge As Bridge = Await client.LocalHueClient.GetBridgeAsync
If LocalHueBridge.IsStreamingActive Then
Console.WriteLine("Streaming is still active....")
'Loop through RGB to show it works
entLayer.SetColor(CancellationToken.None, New RGBColor("FF0000")) 'Set Red
Await Task.Delay(1500)
entLayer.SetColor(CancellationToken.None, New RGBColor("00FF00")) 'Set Green
Await Task.Delay(1500)
entLayer.SetColor(CancellationToken.None, New RGBColor("0000FF")) 'Set Blue
Else
Console.WriteLine("Streaming stopped, Re-enable Streaming ...")
'Connect to the streaming group
Await client.Connect(group.Id)
End If
Await Task.Delay(5000)
Loop
Return True
End Function)
End Sub
End Class
Alright now this works and also restores the Streaming Mode. BUT.... there is a catch... If you open the Hue app and click on STOP streaming than the watchdog will restore it. You will see in the app that StreamingMode is restore, but after a few second it is stopped. And that's the point where you will get an exception on Client.Connect(Id)
. Which is:
Org.BouncyCastle.Crypto.Tls.TlsFatalAlert
HResult=0x80131620
Message=internal_error(80)
Source=BouncyCastle.Crypto
StackTrace:
at Org.BouncyCastle.Crypto.Tls.DtlsClientProtocol.Connect(TlsClient client, DatagramTransport transport) in /_/crypto/src/crypto/tls/DtlsClientProtocol.cs:line 68
at Q42.HueApi.Streaming.StreamingHueClient.<Connect>d__12.MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at Q42HueTest.MainWindow._Closure$__2-0.VB$StateMachine___Lambda$__0.MoveNext() in L:\VisualStudioProjects\Experimenteer\Q42HueTest\Q42HueTest\MainWindow.xaml.vb:line 58
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Q42HueTest.MainWindow.VB$StateMachine_2_Button_Click.MoveNext() in L:\VisualStudioProjects\Experimenteer\Q42HueTest\Q42HueTest\MainWindow.xaml.vb:line 40
This exception was originally thrown at this call stack:
[External Code]
Inner Exception 1:
TimeoutException: The operation has timed out.
This could mean two things:
Client.Connect(Id)
(but i don't think so)Or maybe something else??
It seems that i have got this working now, and this is the code for it:
Class MainWindow
Private entLayer As EntertainmentLayer
Private Async Sub Button_Click(sender As Object, e As RoutedEventArgs)
'Register app with the bridge
Dim streamClientKey As RegisterEntertainmentResult = Await New LocalHueClient("192.168.70.60").RegisterAsync("MyApp", "MyDevice", True)
'Initialize streaming client
Dim client As New StreamingHueClient(streamClientKey.Ip, streamClientKey.Username, streamClientKey.StreamingClientKey)
'Get the entertainment group
Dim all As IReadOnlyList(Of Group) = Await client.LocalHueClient.GetEntertainmentGroups()
Dim group As Group = all.FirstOrDefault()
'Create a streaming group
Dim entGroup As New StreamingGroup(group.Locations)
'Connect to the streaming group
Await client.Connect(group.Id)
'Start auto updating this entertainment group
Dim SetAndForgetTask As Task = client.AutoUpdate(entGroup, CancellationToken.None, 50)
'Create new base layer
entLayer = entGroup.GetNewLayer(True)
entLayer.SetBrightness(CancellationToken.None, 1)
'Setup Watchdog for streaming with auto recovery
Await Task.Run(Async Function()
Do While True
Dim LocalHueBridge As Bridge = Await client.LocalHueClient.GetBridgeAsync
If LocalHueBridge.IsStreamingActive Then
Console.WriteLine("Streaming is still active....")
'Loop through RGB to show it works
entLayer.SetColor(CancellationToken.None, New RGBColor("FF0000")) 'Set Red
Await Task.Delay(500)
entLayer.SetColor(CancellationToken.None, New RGBColor("00FF00")) 'Set Green
Await Task.Delay(500)
entLayer.SetColor(CancellationToken.None, New RGBColor("0000FF")) 'Set Blue
Else
Console.WriteLine("Streaming stopped, Re-enable Streaming ...")
'First we have to close the current socket and setup a new one:
client.Close()
'Now create new StreamingClient
client = New StreamingHueClient(streamClientKey.Ip, streamClientKey.Username, streamClientKey.StreamingClientKey)
'Connect to the streaming group
Await client.Connect(group.Id)
'Start auto updating this entertainment group
SetAndForgetTask = client.AutoUpdate(entGroup, CancellationToken.None, 50)
End If
Await Task.Delay(2500)
Loop
Return True
End Function)
End Sub
End Class
Hi Mark,
Today i created a function where a user can add or remove a light to a Entertainmentgroup using
UpdateGroupAsync
. After the call i noticed than the bridge stops streaming. So i think that we have to setup the Entertainment again? Or is there a simple call likeUpdateStreamingGroup
?