Having covered a basic use case for gRPC streaming of IoT device states in the previous blog post, we’re now moving onto a slightly more complex scenario that involves dynamically broadcasting response streams from the server to any participating clients.
Rather than having each of the gRPC
clients receiving the IoT states update responses to their own request streams, the responses are now being broadcast to all participating clients, making it possible for any given client to work with the received states update of devices inside a property originally processed by other clients.
Akka gRPC streaming
Recall that we were leveraging Akka gRPC to:
- generate service interfaces from the Protobuf service schema that get implemented as Scala classes and Akka stream components to create
HttpRequest => Future[HttpResponse]
routes in the Akka-HTTP server that supports HTTP/2 - generate
gRPC
stubs through implementing the service interfaces with Akka Streams API to invoke the remote services
Dynamically broadcasting IoT streams
Just like in the previous use case, our IoT system of sensor devices consists of a gRPC
server simulating algorithmic changes to device states as response streams to the requesting gRPC
clients. There can be many clients participating/leaving at any time.
In our new use case, the server broadcasts response streams to requests from all clients and each client receives all the stream elements since its participation. It’s similar in some way to a dynamic pub/sub channel in which the gRPC
clients subscribe to a service-topic published by the gRPC
server.
How do we create such a channel? As shown in one of the GreeterService examples available at Lightbend developers guide, we could create one by coupling a MergeHub with a BroadcastHub. For more details, another blog post of mine covers the very topic.
A new Protobuf service
A majority of the source code described in the previous blog post remains unchanged, as we’re only adding a new RPC
service along with its implementation.
First, we declare the new RPC
service broadcastIotUpdate()
in iotstream.proto under src/main/protobuf/
.
service IotStreamService { rpc sendIotUpdate(stream StatesUpdateRequest) returns (stream StatesUpdateResponse) {} rpc broadcastIotUpdate(stream StatesUpdateRequest) returns (stream StatesUpdateResponse) {} }
We then add the implementation of broadcastIotUpdate()
in class IotStreamServiceImpl.
val (inHub: Sink[StatesUpdateRequest, NotUsed], outHub: Source[StatesUpdateResponse, NotUsed]) = MergeHub.source[StatesUpdateRequest] .via(updateIotFlow) .toMat(BroadcastHub.sink[StatesUpdateResponse])(Keep.both) .run() val dynamicPubSubFlow: Flow[StatesUpdateRequest, StatesUpdateResponse, NotUsed] = Flow.fromSinkAndSource(inHub, outHub) ... @Override def broadcastIotUpdate(requests: Source[StatesUpdateRequest, NotUsed]): Source[StatesUpdateResponse, NotUsed] = requests.via(dynamicPubSubFlow).backpressureTimeout(backpressureTMO)
As shown in the above snippet, we “sandwich” updateIotFlow
(which simulates algorithmic IoT states update) between a MergeHub
and a BroadcastHub
to materialize a tuple of sink and source, followed by turning them into the dynamicPubSubFlow
via Akka Stream’s fromSinkAndSource(). The created flow will then serve like a dynamic pub/sub channel funneling incoming request streams from the gRPC
clients to broadcast the response streams with updated states to all participating clients.
As for class IotStreamClient, we add a new command line argument, broadcastYN
(1=Yes, 0=No), to the main()
function’s argument list to indicate whether broadcast of response streams is wanted. The client application will call the specific RPC
service in accordance with the value of broadcastYN
.
val responseStream: Source[StatesUpdateResponse, NotUsed] = { if (broadcastYN == 0) client.sendIotUpdate(requestStream) else client.broadcastIotUpdate(requestStream) }
The following diagram highlights the gRPC
server/clients components, and the rest of the IoT system that manages the individual remote sensor devices. Note that the IoT Manager sub-system isn’t part of the application we’re focusing on. The sub-system could be designed on top of gRPC
as well, or Akka Actors (i.e. similar to the Actor-based IotManager), or any other suitable tech stack.
Full source code for the gRPC
client/server components is available at this GitHub repo.
Final thoughts
It should be noted that this is a simplified use case primarily for demonstrating how device states update from the gRPC
server can be dynamically broadcast to the requesting clients. To strengthen the use case, we could maintain a key-value cache using Redis with unique device IDs as keys subject to a pre-set TTL (time-to-live) to prevent multiple gRPC
clients processing for the same device simultaneously.
In addition, we might also log in persistence storages the who-what-and-when (i.e. client ID / states / timestamp) of the device states update, or if warranted by the business requirement, putting in place a distributed committed log system with Apache Kafka. Such enhancement would enable the Akka Streams-baced gRPC
tech stack to provide a robust streaming mechanism comparable to those solutions like using Akka Actors with distributed pub/sub and persistence journal on clusters.
Sample output
Appended is sample output from the gRPC
server and 3 gRPC
clients. As shown in the output, one could mix and match clients with different broadcast
options, in which case the group of clients with broadcast
on will share among themselves all streams responded by the server to requests from themselves, whereas each member of the broadcast
-off group will get only responded streams originated by itself.
Terminal #1: gRPC
Server
% ./sbt "runMain akkagrpc.IotStreamServer" [info] ... [info] done compiling [info] running (fork) akkagrpc.IotStreamServer [info] [2023-10-31 11:38:03,227] [INFO] [akka.event.slf4j.Slf4jLogger] [IotStreamServer-akka.actor.default-dispatcher-3] [] - Slf4jLogger started [info] [Server] gRPC server bound to 127.0.0.1:8080
Terminal #2: gRPC
Client1 — broadcast ON (broadcastYN = 1)
% ./sbt "runMain akkagrpc.IotStreamClient client1 1 1000 1019" [info] welcome to sbt 1.9.6 (Oracle Corporation Java 11.0.19) [info] loading global plugins from /Users/leo/.sbt/1.0/plugins [info] loading settings for project akka-grpc-iot-stream-build from plugins.sbt ... [info] loading project definition from /Users/leo/intellij/akka-grpc-iot-stream/project [info] loading settings for project akka-grpc-iot-stream from build.sbt ... [info] set current project to akka-grpc-iot-stream (in build file:/Users/leo/intellij/akka-grpc-iot-stream/) [info] running (fork) akkagrpc.IotStreamClient client1 1 1000 1019 [info] [2023-10-31 11:53:39,910] [INFO] [akka.event.slf4j.Slf4jLogger] [IotStreamClient-akka.actor.default-dispatcher-3] [] - Slf4jLogger started [info] Performing streaming requests from client1 ... [info] [client1] REQUEST: 1000 5e468f SecurityAlarm | State: 0, Setting: 1 [info] [client1] REQUEST: 1000 70a7bf Lamp | State: 0, Setting: 2 [info] [client1] REQUEST: 1001 a6d07c Lamp | State: 1, Setting: 1 [info] [client1] REQUEST: 1001 b224cf SecurityAlarm | State: 0, Setting: 4 [info] [client1] REQUEST: 1001 df00a1 SecurityAlarm | State: 1, Setting: 4 [info] [client1] REQUEST: 1002 5d9abe Thermostat | State: 1, Setting: 69 [info] [client1] REQUEST: 1002 283a39 Thermostat | State: 1, Setting: 60 [info] [client1] REQUEST: 1002 70b354 SecurityAlarm | State: 0, Setting: 5 [info] [client1] REQUEST: 1002 c12ac7 Thermostat | State: 0, Setting: 66 [info] [client1] REQUEST: 1003 2587a9 Lamp | State: 0, Setting: 2 [info] [client1] REQUEST: 1004 f5732a Thermostat | State: 1, Setting: 62 [info] [client1] REQUEST: 1004 c7aaf1 Lamp | State: 0, Setting: 1 [info] [client1] RESPONSE: [requester: client1] 1000 5e468f SecurityAlarm | State: 0, Setting: 5 [info] [client1] RESPONSE: [requester: client1] 1000 70a7bf Lamp | State: 0, Setting: 3 [info] [client1] RESPONSE: [requester: client1] 1001 a6d07c Lamp | State: 0, Setting: 1 [info] [client1] RESPONSE: [requester: client1] 1001 b224cf SecurityAlarm | State: 0, Setting: 4 [info] [client1] RESPONSE: [requester: client1] 1001 df00a1 SecurityAlarm | State: 1, Setting: 3 [info] [client1] RESPONSE: [requester: client1] 1002 5d9abe Thermostat | State: 1, Setting: 67 [info] [client1] RESPONSE: [requester: client1] 1002 283a39 Thermostat | State: 0, Setting: 60 [info] [client1] RESPONSE: [requester: client1] 1002 70b354 SecurityAlarm | State: 0, Setting: 4 [info] [client1] RESPONSE: [requester: client1] 1002 c12ac7 Thermostat | State: 2, Setting: 64 [info] [client1] RESPONSE: [requester: client1] 1003 2587a9 Lamp | State: 0, Setting: 1 [info] [client1] RESPONSE: [requester: client1] 1004 f5732a Thermostat | State: 0, Setting: 63 [info] [client1] REQUEST: 1004 72a5f5 SecurityAlarm | State: 0, Setting: 2 [info] [client1] RESPONSE: [requester: client1] 1004 c7aaf1 Lamp | State: 1, Setting: 2 [info] [client1] REQUEST: 1005 f859d3 Thermostat | State: 2, Setting: 70 [info] [client1] RESPONSE: [requester: client1] 1004 72a5f5 SecurityAlarm | State: 0, Setting: 3 [info] [client1] REQUEST: 1006 4a7da5 SecurityAlarm | State: 0, Setting: 2 [info] [client1] RESPONSE: [requester: client1] 1005 f859d3 Thermostat | State: 0, Setting: 70 [info] [client1] REQUEST: 1006 17ac1a Lamp | State: 0, Setting: 3 [info] [client1] RESPONSE: [requester: client1] 1006 4a7da5 SecurityAlarm | State: 0, Setting: 2 [info] [client1] REQUEST: 1006 58653a Lamp | State: 0, Setting: 2 [info] [client1] RESPONSE: [requester: client1] 1006 17ac1a Lamp | State: 0, Setting: 1 [info] [client1] REQUEST: 1006 0bfa66 SecurityAlarm | State: 1, Setting: 5 [info] [client1] RESPONSE: [requester: client1] 1006 58653a Lamp | State: 0, Setting: 2 [info] [client1] REQUEST: 1007 6caf32 SecurityAlarm | State: 0, Setting: 2 [info] [client1] RESPONSE: [requester: client1] 1006 0bfa66 SecurityAlarm | State: 0, Setting: 2 [info] [client1] REQUEST: 1007 2b67a7 SecurityAlarm | State: 0, Setting: 1 [info] [client1] RESPONSE: [requester: client1] 1007 6caf32 SecurityAlarm | State: 0, Setting: 4 [info] [client1] RESPONSE: [requester: client3] 1040 f237b5 Lamp | State: 1, Setting: 3 [info] [client1] RESPONSE: [requester: client3] 1040 cbeb82 SecurityAlarm | State: 1, Setting: 2 [info] [client1] RESPONSE: [requester: client3] 1040 742dcd Thermostat | State: 1, Setting: 70 [info] [client1] RESPONSE: [requester: client3] 1041 337d19 Lamp | State: 1, Setting: 2 [info] [client1] RESPONSE: [requester: client3] 1041 6d19d6 Thermostat | State: 1, Setting: 64 [info] [client1] RESPONSE: [requester: client3] 1041 144297 Thermostat | State: 0, Setting: 69 [info] [client1] RESPONSE: [requester: client3] 1041 663271 SecurityAlarm | State: 1, Setting: 2 [info] [client1] RESPONSE: [requester: client3] 1042 83807a Lamp | State: 1, Setting: 1 [info] [client1] RESPONSE: [requester: client3] 1042 5ce343 Thermostat | State: 2, Setting: 60 [info] [client1] RESPONSE: [requester: client3] 1042 7ab082 Lamp | State: 1, Setting: 1 [info] [client1] RESPONSE: [requester: client3] 1042 eae803 Thermostat | State: 2, Setting: 65 [info] [client1] REQUEST: 1008 f0c753 Thermostat | State: 2, Setting: 67 [info] [client1] RESPONSE: [requester: client1] 1007 2b67a7 SecurityAlarm | State: 0, Setting: 1 [info] [client1] RESPONSE: [requester: client3] 1043 88ee61 Lamp | State: 0, Setting: 2 [info] [client1] REQUEST: 1008 32ccb2 Lamp | State: 0, Setting: 2 [info] [client1] RESPONSE: [requester: client1] 1008 f0c753 Thermostat | State: 2, Setting: 65 [info] [client1] RESPONSE: [requester: client3] 1043 440b5b Lamp | State: 1, Setting: 3 . . . . . . [info] [client1] REQUEST: 1019 3f122b Thermostat | State: 0, Setting: 63 [info] [client1] RESPONSE: [requester: client1] 1019 6f15e0 Lamp | State: 1, Setting: 1 [info] [client1] RESPONSE: [requester: client3] 1055 6a6fde Lamp | State: 0, Setting: 2 [info] [client1] REQUEST: 1019 b8ce7b SecurityAlarm | State: 1, Setting: 5 [info] [client1] RESPONSE: [requester: client1] 1019 3f122b Thermostat | State: 1, Setting: 64 [info] [client1] RESPONSE: [requester: client3] 1056 60eab7 Thermostat | State: 2, Setting: 70 [info] [client1] REQUEST: 1019 93678e SecurityAlarm | State: 0, Setting: 3 [info] [client1] RESPONSE: [requester: client1] 1019 b8ce7b SecurityAlarm | State: 1, Setting: 5 [info] [client1] RESPONSE: [requester: client3] 1056 ae65ad Thermostat | State: 0, Setting: 66 [info] [client1] RESPONSE: [requester: client1] 1019 93678e SecurityAlarm | State: 1, Setting: 4 [info] [client1] RESPONSE: [requester: client3] 1056 cb5d9f Lamp | State: 0, Setting: 1 [info] [client1] RESPONSE: [requester: client3] 1057 c4abf5 Thermostat | State: 0, Setting: 73 [info] [client1] RESPONSE: [requester: client3] 1058 013a30 SecurityAlarm | State: 1, Setting: 5 [info] [client1] RESPONSE: [requester: client3] 1058 681c43 Lamp | State: 1, Setting: 2 [info] [client1] RESPONSE: [requester: client3] 1058 0f1673 Thermostat | State: 1, Setting: 65 [info] [client1] RESPONSE: [requester: client3] 1058 0c97dd Lamp | State: 1, Setting: 3 [info] [client1] RESPONSE: [requester: client3] 1059 e9834d Lamp | State: 1, Setting: 2 [info] [client1] RESPONSE: [requester: client3] 1059 93166b Thermostat | State: 1, Setting: 73
Terminal #3: gRPC
Client2 — broadcast OFF (broadcastYN = 0)
% ./sbt "runMain akkagrpc.IotStreamClient client2 0 1020 1039" [info] welcome to sbt 1.9.6 (Oracle Corporation Java 11.0.19) [info] loading global plugins from /Users/leo/.sbt/1.0/plugins [info] loading settings for project akka-grpc-iot-stream-build from plugins.sbt ... [info] loading project definition from /Users/leo/intellij/akka-grpc-iot-stream/project [info] loading settings for project akka-grpc-iot-stream from build.sbt ... [info] set current project to akka-grpc-iot-stream (in build file:/Users/leo/intellij/akka-grpc-iot-stream/) [info] running (fork) akkagrpc.IotStreamClient client2 0 1020 1039 [info] [2023-10-31 11:53:40,601] [INFO] [akka.event.slf4j.Slf4jLogger] [IotStreamClient-akka.actor.default-dispatcher-3] [] - Slf4jLogger started [info] Performing streaming requests from client2 ... [info] [client2] REQUEST: 1020 be1091 Lamp | State: 1, Setting: 3 [info] [client2] REQUEST: 1021 9e6b12 SecurityAlarm | State: 0, Setting: 3 [info] [client2] REQUEST: 1021 cf913c Thermostat | State: 1, Setting: 69 [info] [client2] REQUEST: 1022 4549d2 Lamp | State: 0, Setting: 1 [info] [client2] REQUEST: 1022 08e429 Thermostat | State: 2, Setting: 60 [info] [client2] REQUEST: 1023 aa1eea Lamp | State: 1, Setting: 3 [info] [client2] REQUEST: 1023 af1da0 Thermostat | State: 0, Setting: 70 [info] [client2] REQUEST: 1023 9e7439 Thermostat | State: 0, Setting: 64 [info] [client2] REQUEST: 1023 b21319 SecurityAlarm | State: 0, Setting: 4 [info] [client2] REQUEST: 1024 6ce4c5 SecurityAlarm | State: 1, Setting: 1 [info] [client2] REQUEST: 1024 827653 Thermostat | State: 0, Setting: 64 [info] [client2] REQUEST: 1024 ae359e SecurityAlarm | State: 0, Setting: 1 [info] [client2] RESPONSE: [requester: client2] 1020 be1091 Lamp | State: 0, Setting: 3 [info] [client2] RESPONSE: [requester: client2] 1021 9e6b12 SecurityAlarm | State: 0, Setting: 3 [info] [client2] RESPONSE: [requester: client2] 1021 cf913c Thermostat | State: 1, Setting: 67 [info] [client2] RESPONSE: [requester: client2] 1022 4549d2 Lamp | State: 0, Setting: 3 [info] [client2] RESPONSE: [requester: client2] 1022 08e429 Thermostat | State: 2, Setting: 61 [info] [client2] RESPONSE: [requester: client2] 1023 aa1eea Lamp | State: 1, Setting: 1 [info] [client2] RESPONSE: [requester: client2] 1023 af1da0 Thermostat | State: 2, Setting: 72 [info] [client2] RESPONSE: [requester: client2] 1023 9e7439 Thermostat | State: 2, Setting: 65 [info] [client2] RESPONSE: [requester: client2] 1023 b21319 SecurityAlarm | State: 0, Setting: 3 [info] [client2] RESPONSE: [requester: client2] 1024 6ce4c5 SecurityAlarm | State: 1, Setting: 5 [info] [client2] RESPONSE: [requester: client2] 1024 827653 Thermostat | State: 0, Setting: 64 [info] [client2] REQUEST: 1024 9b4378 Thermostat | State: 1, Setting: 64 [info] [client2] RESPONSE: [requester: client2] 1024 ae359e SecurityAlarm | State: 0, Setting: 1 [info] [client2] REQUEST: 1025 66f837 Lamp | State: 0, Setting: 1 [info] [client2] RESPONSE: [requester: client2] 1024 9b4378 Thermostat | State: 1, Setting: 66 [info] [client2] REQUEST: 1026 b0ac08 SecurityAlarm | State: 1, Setting: 3 [info] [client2] RESPONSE: [requester: client2] 1025 66f837 Lamp | State: 0, Setting: 1 [info] [client2] REQUEST: 1027 249cb9 SecurityAlarm | State: 0, Setting: 5 [info] [client2] RESPONSE: [requester: client2] 1026 b0ac08 SecurityAlarm | State: 0, Setting: 4 [info] [client2] REQUEST: 1027 d205d3 Lamp | State: 1, Setting: 2 [info] [client2] RESPONSE: [requester: client2] 1027 249cb9 SecurityAlarm | State: 0, Setting: 1 [info] [client2] REQUEST: 1027 6783fc Lamp | State: 0, Setting: 1 . . . . . . [info] [client2] REQUEST: 1038 af2956 Lamp | State: 0, Setting: 1 [info] [client2] RESPONSE: [requester: client2] 1037 ed954a Lamp | State: 0, Setting: 2 [info] [client2] REQUEST: 1038 656d9f Thermostat | State: 1, Setting: 63 [info] [client2] RESPONSE: [requester: client2] 1038 af2956 Lamp | State: 1, Setting: 3 [info] [client2] REQUEST: 1039 582904 Lamp | State: 1, Setting: 3 [info] [client2] RESPONSE: [requester: client2] 1038 656d9f Thermostat | State: 0, Setting: 62 [info] [client2] REQUEST: 1039 5daf4a SecurityAlarm | State: 0, Setting: 3 [info] [client2] RESPONSE: [requester: client2] 1039 582904 Lamp | State: 1, Setting: 1 [info] [client2] REQUEST: 1039 e31886 Thermostat | State: 1, Setting: 75 [info] [client2] RESPONSE: [requester: client2] 1039 5daf4a SecurityAlarm | State: 1, Setting: 5 [info] [client2] RESPONSE: [requester: client2] 1039 e31886 Thermostat | State: 0, Setting: 75 [info] [client2] Done IoT states streaming.
Terminal #4: gRPC
Client3 — broadcast ON (broadcastYN = 1)
% ./sbt "runMain akkagrpc.IotStreamClient client3 1 1040 1059" [info] welcome to sbt 1.9.6 (Oracle Corporation Java 11.0.19) [info] loading global plugins from /Users/leo/.sbt/1.0/plugins [info] loading settings for project akka-grpc-iot-stream-build from plugins.sbt ... [info] loading project definition from /Users/leo/intellij/akka-grpc-iot-stream/project [info] loading settings for project akka-grpc-iot-stream from build.sbt ... [info] set current project to akka-grpc-iot-stream (in build file:/Users/leo/intellij/akka-grpc-iot-stream/) [info] running (fork) akkagrpc.IotStreamClient client3 1 1040 1059 [info] [2023-10-31 11:53:40,842] [INFO] [akka.event.slf4j.Slf4jLogger] [IotStreamClient-akka.actor.default-dispatcher-3] [] - Slf4jLogger started [info] Performing streaming requests from client3 ... [info] [client3] REQUEST: 1040 f237b5 Lamp | State: 0, Setting: 3 [info] [client3] REQUEST: 1040 cbeb82 SecurityAlarm | State: 0, Setting: 2 [info] [client3] REQUEST: 1040 742dcd Thermostat | State: 1, Setting: 72 [info] [client3] REQUEST: 1041 337d19 Lamp | State: 1, Setting: 2 [info] [client3] REQUEST: 1041 6d19d6 Thermostat | State: 1, Setting: 65 [info] [client3] REQUEST: 1041 144297 Thermostat | State: 2, Setting: 68 [info] [client3] REQUEST: 1041 663271 SecurityAlarm | State: 1, Setting: 3 [info] [client3] REQUEST: 1042 83807a Lamp | State: 1, Setting: 2 [info] [client3] REQUEST: 1042 5ce343 Thermostat | State: 0, Setting: 60 [info] [client3] REQUEST: 1042 7ab082 Lamp | State: 1, Setting: 1 [info] [client3] REQUEST: 1042 eae803 Thermostat | State: 0, Setting: 65 [info] [client3] REQUEST: 1043 88ee61 Lamp | State: 1, Setting: 3 [info] [client3] RESPONSE: [requester: client3] 1040 f237b5 Lamp | State: 1, Setting: 3 [info] [client3] RESPONSE: [requester: client3] 1040 cbeb82 SecurityAlarm | State: 1, Setting: 2 [info] [client3] RESPONSE: [requester: client3] 1040 742dcd Thermostat | State: 1, Setting: 70 [info] [client3] RESPONSE: [requester: client3] 1041 337d19 Lamp | State: 1, Setting: 2 [info] [client3] RESPONSE: [requester: client3] 1041 6d19d6 Thermostat | State: 1, Setting: 64 [info] [client3] RESPONSE: [requester: client3] 1041 144297 Thermostat | State: 0, Setting: 69 [info] [client3] RESPONSE: [requester: client3] 1041 663271 SecurityAlarm | State: 1, Setting: 2 [info] [client3] RESPONSE: [requester: client3] 1042 83807a Lamp | State: 1, Setting: 1 [info] [client3] RESPONSE: [requester: client3] 1042 5ce343 Thermostat | State: 2, Setting: 60 [info] [client3] RESPONSE: [requester: client3] 1042 7ab082 Lamp | State: 1, Setting: 1 [info] [client3] RESPONSE: [requester: client3] 1042 eae803 Thermostat | State: 2, Setting: 65 [info] [client3] RESPONSE: [requester: client1] 1007 2b67a7 SecurityAlarm | State: 0, Setting: 1 [info] [client3] REQUEST: 1043 440b5b Lamp | State: 0, Setting: 1 [info] [client3] RESPONSE: [requester: client3] 1043 88ee61 Lamp | State: 0, Setting: 2 [info] [client3] RESPONSE: [requester: client1] 1008 f0c753 Thermostat | State: 2, Setting: 65 [info] [client3] REQUEST: 1043 99c6e0 SecurityAlarm | State: 1, Setting: 1 [info] [client3] RESPONSE: [requester: client3] 1043 440b5b Lamp | State: 1, Setting: 3 [info] [client3] RESPONSE: [requester: client1] 1008 32ccb2 Lamp | State: 0, Setting: 2 [info] [client3] REQUEST: 1044 de863b Lamp | State: 1, Setting: 2 [info] [client3] RESPONSE: [requester: client3] 1043 99c6e0 SecurityAlarm | State: 1, Setting: 5 [info] [client3] RESPONSE: [requester: client1] 1009 edf984 SecurityAlarm | State: 1, Setting: 5 [info] [client3] REQUEST: 1044 04dff8 Lamp | State: 0, Setting: 1 [info] [client3] RESPONSE: [requester: client3] 1044 de863b Lamp | State: 1, Setting: 2 [info] [client3] RESPONSE: [requester: client1] 1009 274bca Thermostat | State: 2, Setting: 68 [info] [client3] REQUEST: 1044 86ed37 SecurityAlarm | State: 1, Setting: 1 [info] [client3] RESPONSE: [requester: client3] 1044 04dff8 Lamp | State: 0, Setting: 1 [info] [client3] RESPONSE: [requester: client1] 1009 50e02f Thermostat | State: 1, Setting: 66 [info] [client3] REQUEST: 1044 fd5984 SecurityAlarm | State: 0, Setting: 3 [info] [client3] RESPONSE: [requester: client3] 1044 86ed37 SecurityAlarm | State: 1, Setting: 5 [info] [client3] RESPONSE: [requester: client1] 1009 c6160b SecurityAlarm | State: 1, Setting: 5 [info] [client3] REQUEST: 1045 a6b326 Thermostat | State: 0, Setting: 60 [info] [client3] RESPONSE: [requester: client3] 1044 fd5984 SecurityAlarm | State: 1, Setting: 1 [info] [client3] RESPONSE: [requester: client1] 1010 eb624d SecurityAlarm | State: 0, Setting: 4 . . . . . . [info] [client3] REQUEST: 1057 c4abf5 Thermostat | State: 2, Setting: 73 [info] [client3] RESPONSE: [requester: client3] 1056 cb5d9f Lamp | State: 0, Setting: 1 [info] [client3] REQUEST: 1058 013a30 SecurityAlarm | State: 1, Setting: 5 [info] [client3] RESPONSE: [requester: client3] 1057 c4abf5 Thermostat | State: 0, Setting: 73 [info] [client3] REQUEST: 1058 681c43 Lamp | State: 1, Setting: 3 [info] [client3] RESPONSE: [requester: client3] 1058 013a30 SecurityAlarm | State: 1, Setting: 5 [info] [client3] REQUEST: 1058 0f1673 Thermostat | State: 1, Setting: 64 [info] [client3] RESPONSE: [requester: client3] 1058 681c43 Lamp | State: 1, Setting: 2 [info] [client3] REQUEST: 1058 0c97dd Lamp | State: 1, Setting: 3 [info] [client3] RESPONSE: [requester: client3] 1058 0f1673 Thermostat | State: 1, Setting: 65 [info] [client3] REQUEST: 1059 e9834d Lamp | State: 0, Setting: 2 [info] [client3] RESPONSE: [requester: client3] 1058 0c97dd Lamp | State: 1, Setting: 3 [info] [client3] REQUEST: 1059 93166b Thermostat | State: 0, Setting: 71 [info] [client3] RESPONSE: [requester: client3] 1059 e9834d Lamp | State: 1, Setting: 2 [info] [client3] RESPONSE: [requester: client3] 1059 93166b Thermostat | State: 1, Setting: 73