How to get Web Bluetooth to send multiple `characteristicvaluechanged` events? - web-bluetooth

[paraphrasing an IRC conversation]
Trying to build a temperature sensor with ardunio and a DHT11 sensor and a HM10 bluetooth sensor. When getting the temperature values with Web Bluetooth but it doesn't seem to be firing the characteristicvaluechanged event. It only gives the initial value.
document.querySelector('button')
.addEventListener('click', connectBluetooth)
function connectBluetooth() {
navigator.bluetooth
.requestDevice({
optionalServices: [ 0xffe0 ],
acceptAllDevices: true
})
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService(0xffe0))
.then(service => service.getCharacteristic(0xffe1))
.then(characteristic => {
characteristic.addEventListener('characteristicvaluechanged',
handleValueChanged)
return characteristic.readValue()
})
.catch(err => console.error(err))
}
function handleValueChanged(event) {
console.log('Handling...')
let value = event.target.value.getUint8(0)
console.log(`The value is: ${value}`)
}

You never subscribed to notifications. See https://googlechrome.github.io/samples/web-bluetooth/notifications.html for an example. Registering the event listener is not sufficient, you must also call characteristic.startNotifications(). The readValue was returning one result, so just replace it with startNotifications.

Related

React Redux dispatch getting called multiple times

MERN Stack application with Login and Register working properly.
On opening dashboard ("/" path), it dispatches "getWallets" 3 times, instead of 1:
Dashboard.jsx :
useEffect(() => {
if (isError) {
console.log(message)
}
if (!user) {
navigate("/login")
}
else {
dispatch(getWallets())
}
return () => {
dispatch(reset())
}
}, [user, navigate, isError, message, dispatch])
It also dispatches "getWalletData" 9 times instead of one (since I only have 1 wallet atm).
TestWalletsData.jsx (component inserted on Dashboard.jsx):
useEffect(() => {
if (isError) {
console.log(message)
}
if (wallets.length > 0 && walletsData.length <= wallets.length) {
wallets.forEach(wallet => {
dispatch(getWalletData(wallet))
dispatch(reset())
})
}
return () => {
dispatch(reset())
}
}, [wallets, wallets.length, walletsData, isError, message, dispatch])
At this point the application is running ok since I don't permit another object to get pushed to the state if it's already there , but since I'm using a limited rate API to get wallets data this isn't the road I want to path.
I'm assuming the issue arrives with the re-rendering of components and the wrong use of useEffect, but I just don't know how to fix it.
I've tried setting the environment to production as suggested by this comment but everything stays the same. https://stackoverflow.com/a/72301433/14399239
PS: Never worked with React Redux or Redux for that matter before trying it out on this project. Tried to follow a tutorial logic and apply it on my use case but having serious difficulties.
EDIT
Managed to solve the issue by removing the React.StrictMode !

Checking if host is online in Cypress

My tests run on a IOT device which is controlled via a web interface. I want to create a factory reset test which involves a reboot of the device and I want to check in a loop if the device is online ("pingable") again. Is there a way to execute the ping command inside of Cypress and get a return value of it.
Presuming you mean the standard ping protocol, this is the form. Substitute your device address and reply message.
cy.exec('ping google.com')
.then(reply => {
expect(reply.code).to.eq(0)
const expectedMsg = 'Pinging google.com [142.250.66.206] with 32 bytes of data:\r\nReply from 142.250.66.206: bytes=32'
expect(reply.stdout).to.satisfy(msg => msg.startsWith(expectedMsg))
})
A loop may not be needed, but if so I'd use a recursive function
function doPing(count = 0) {
if (count === 10) throw 'Failed to ping';
cy.exec('ping google.com')
.then(reply => {
if (reply.code > 0) {
cy.wait(1000) // whatever back-off time is required
doPing(++count)
} else {
expect(reply.stdout).to.satisfy(msg => ...)
}
})
}
doPing()

What is the correct way to start a MassTransit bus when using the CreateRequestClient method?

I'm using the following code to send a request/response message between two different processes.
This is the process that "sends" the request:
// configure host
var hostUri = new Uri(configuration["RabbitMQ:Host"]);
services.AddSingleton(provider => Bus.Factory.CreateUsingRabbitMq(cfg =>
{
var host = cfg.Host(hostUri, h =>
{
h.Username(configuration["RabbitMQ:Username"]);
h.Password(configuration["RabbitMQ:Password"]);
});
}));
// add request client
services.AddScoped(provider => provider.GetRequiredService<IBus>().CreateRequestClient<QueryUserInRole, QueryUserInRoleResult>(new Uri(hostUri, "focus-authorization"), TimeSpan.FromSeconds(5)));
// add dependencies
services.AddSingleton<IPublishEndpoint>(provider => provider.GetRequiredService<IBusControl>());
services.AddSingleton<ISendEndpointProvider>(provider => provider.GetRequiredService<IBusControl>());
services.AddSingleton<IBus>(provider => provider.GetRequiredService<IBusControl>());
// add the service class so that the runtime can automatically handle the start and stop of our bus
services.AddSingleton<Microsoft.Extensions.Hosting.IHostedService, BusService>();
Here's the implementation of the BusService:
public class BusService : Microsoft.Extensions.Hosting.IHostedService
{
private readonly IBusControl _busControl;
public BusService(IBusControl busControl)
{
_busControl = busControl;
}
public Task StartAsync(CancellationToken cancellationToken)
{
return _busControl.StartAsync(cancellationToken);
}
public Task StopAsync(CancellationToken cancellationToken)
{
return _busControl.StopAsync(cancellationToken);
}
}
The problem is that when the CreateRequestClient code runs, the bus has not started up yet. Thus the response is never returned from the consumer.
If I replace the host configuration with the following code, I get the desired behavior:
var bus = Bus.Factory.CreateUsingRabbitMq(cfg =>
{
var host = cfg.Host(hostUri, h =>
{
h.Username(configuration["RabbitMQ:Username"]);
h.Password(configuration["RabbitMQ:Password"]);
});
});
bus.Start();
services.AddSingleton(bus);
For some reason, the BusService(IHostedService) executes AFTER the AddScoped delegates.
My question is: what is the correct way to start up the bus before using the CreateRequestClient method? Or is the latter approach to starting up the bus sufficient?

Cyclejs Read/write websocket driver?

I'm new to cyclejs and I'm looking for websocket support and I don't see any (apart from the read only websocket driver from the docs and some 0.1.2 node side npm package).
Am I supposed to create my own driver or am I missing something?
Thanks in advance
Does this page help you?
https://cycle.js.org/drivers.html
Specifically the example code mentioned:
function WSDriver(/* no sinks */) {
return xs.create({
start: listener => {
this.connection = new WebSocket('ws://localhost:4000');
connection.onerror = (err) => {
listener.error(err)
}
connection.onmessage = (msg) => {
listener.next(msg)
}
},
stop: () => {
this.connection.close();
},
});
}
If you add a sink this should be a write and read driver. From their documentation:
Most drivers, like the DOM Driver, take sinks (to describe a write) and return sources (to catch reads). However, we might have valid cases for write-only drivers and read-only drivers.
For instance, the one-liner log driver we just saw above is a write-only driver. Notice how it is a function that does not return any stream, it simply consumes the sink msg$ it receives.
Other drivers only create source streams that emit events to the main(), but don’t take in any sink from main(). An example of such would be a read-only Web Socket driver, drafted below:

Using side effects in Akka Streams to implement commands received from a websocket

I want to be able to click a button on a website, have it represent a command, issue that command to my program via a websocket, have my program process that command (which will produce a side effect), and then return the results of that command to the website to be rendered.
The websocket would be responsible for updating state changes applied by different actors that are within the users view.
Example: Changing AI instructions via the website. This modifies some values, which would get reported back to the website. Other users might change other AI instructions, or the AI would react to current conditions changing position, requiring the client to update the screen.
I was thinking I could have an actor responsible for updating the client with changed information, and just have the receiving stream update the state with the changes?
Is this the right library to use? Is there a better method to achieve what I want?
You can use akka-streams and akka-http for this just fine. An example when using an actor as a handler:
package test
import akka.actor.{Actor, ActorRef, ActorSystem, Props, Stash, Status}
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.ws.{Message, TextMessage}
import akka.http.scaladsl.server.Directives._
import akka.stream.scaladsl.{Flow, Sink, Source, SourceQueueWithComplete}
import akka.stream.{ActorMaterializer, OverflowStrategy, QueueOfferResult}
import akka.pattern.pipe
import scala.concurrent.{ExecutionContext, Future}
import scala.io.StdIn
object Test extends App {
implicit val actorSystem = ActorSystem()
implicit val materializer = ActorMaterializer()
implicit def executionContext: ExecutionContext = actorSystem.dispatcher
val routes =
path("talk") {
get {
val handler = actorSystem.actorOf(Props[Handler])
val flow = Flow.fromSinkAndSource(
Flow[Message]
.filter(_.isText)
.mapAsync(4) {
case TextMessage.Strict(text) => Future.successful(text)
case TextMessage.Streamed(textStream) => textStream.runReduce(_ + _)
}
.to(Sink.actorRefWithAck[String](handler, Handler.Started, Handler.Ack, Handler.Completed)),
Source.queue[String](16, OverflowStrategy.backpressure)
.map(TextMessage.Strict)
.mapMaterializedValue { queue =>
handler ! Handler.OutputQueue(queue)
queue
}
)
handleWebSocketMessages(flow)
}
}
val bindingFuture = Http().bindAndHandle(routes, "localhost", 8080)
println("Started the server, press enter to shutdown")
StdIn.readLine()
bindingFuture
.flatMap(_.unbind())
.onComplete(_ => actorSystem.terminate())
}
object Handler {
case object Started
case object Completed
case object Ack
case class OutputQueue(queue: SourceQueueWithComplete[String])
}
class Handler extends Actor with Stash {
import context.dispatcher
override def receive: Receive = initialReceive
def initialReceive: Receive = {
case Handler.Started =>
println("Client has connected, waiting for queue")
context.become(waitQueue)
sender() ! Handler.Ack
case Handler.OutputQueue(queue) =>
println("Queue received, waiting for client")
context.become(waitClient(queue))
}
def waitQueue: Receive = {
case Handler.OutputQueue(queue) =>
println("Queue received, starting")
context.become(running(queue))
unstashAll()
case _ =>
stash()
}
def waitClient(queue: SourceQueueWithComplete[String]): Receive = {
case Handler.Started =>
println("Client has connected, starting")
context.become(running(queue))
sender() ! Handler.Ack
unstashAll()
case _ =>
stash()
}
case class ResultWithSender(originalSender: ActorRef, result: QueueOfferResult)
def running(queue: SourceQueueWithComplete[String]): Receive = {
case s: String =>
// do whatever you want here with the received message
println(s"Received text: $s")
val originalSender = sender()
queue
.offer("some response to the client")
.map(ResultWithSender(originalSender, _))
.pipeTo(self)
case ResultWithSender(originalSender, result) =>
result match {
case QueueOfferResult.Enqueued => // okay
originalSender ! Handler.Ack
case QueueOfferResult.Dropped => // due to the OverflowStrategy.backpressure this should not happen
println("Could not send the response to the client")
originalSender ! Handler.Ack
case QueueOfferResult.Failure(e) =>
println(s"Could not send the response to the client: $e")
context.stop(self)
case QueueOfferResult.QueueClosed =>
println("Outgoing connection to the client has closed")
context.stop(self)
}
case Handler.Completed =>
println("Client has disconnected")
queue.complete()
context.stop(self)
case Status.Failure(e) =>
println(s"Client connection has failed: $e")
e.printStackTrace()
queue.fail(new RuntimeException("Upstream has failed", e))
context.stop(self)
}
}
There are lots of places here which could be tweaked, but the basic idea remains the same. Alternatively, you could implement the Flow[Message, Message, _] required by the handleWebSocketMessages() method by using GraphStage. Everything used above is also described in detail in akka-streams documentation.

Resources