Function Node-red Raspberry - while-loop

I am testing with my new Raspberry Pi and starting with the Node-red and I have encountered an obstacle.
I try to make a loop which ends when a switch is triggered, but when it enters the while loop it does not re-read the "alarm" variable and loop infinitely.
context.data = context.data || {};
switch (msg.topic){
case "alarma":
context.data.alarma = msg.payload;
msg = null;
break;
case "pi/13":
context.data.contacto = msg.payload;
msg = null;
break;
}
if(context.data.alarma === true && context.data.contacto == 1)
{
while(context.data.alarma === true)
{
context.data.alarma = msg.payload;
node.send({payload:true});
}
}
return {payload:"stop"};
I have tried putting all the code in a "do - while" loop but it fails, I have also tried to put the whole switch block back into the while and the same thing. Any ideas?
I'm making an alarm system, for this I have a switch (to activate and deactivate the alarm) and a contact in a door. If the alarm is activated and the contact opens, the alarm sounds (I return true), the alarm will be disconnected if I close the contact again (that is not what I pretend) I want that only disconnect if the alarm deactivation switch is activated. If I do not turn off the switch I want it to return true so the alarm will continue to ring. I have also tried to introduce a delay so the while loop is not so fast, but still not working. What I want is to know how to actually the variable inside the loop.
Thank you!!

That's because the variable will probably never actually change, that loop will just run so tight and never return so Node-RED will not get a chance to process any messages that would change the variable.
It will also be sending 1000's of message with payload: true
You should not need the loop at all, just return {payload: true} in the if else return {payload: 'stop'} (should that be false rather than stop?)
if(context.data.alarma === true && context.data.contacto == 1)
{
return {payload:true});
} else {
return {payload:"stop"};
}

Related

WebRTC - RTCPeerConnection.onconnectionstatechange fires with RTCPeerConnection.connectionState = 'disconnected' without any reason

I am working on the WebRTC application for video chatting. On my local network everything works well. But when I try it to test through internet RTCPeerConnection.onconnectionstatechange fires with RTCPeerConnection.connectionState = 'disconnected' without any reason after some 20-30 seconds of communication. Another very confusing thing is that for example I have peer2 and peer3 started in the same browser in different tabs connected to peer1 and peer1 videostreaming to them. And after 20-30 seconds RTCPeerConnection.connectionState = 'disconnected' can fire on peer2 and at the same time peer3 continues to receive video stream from peer1. I have googled a bit and found this solution (which doesnt work in my case):
this.myRTCMediaMediatorConnections[id][hash].onconnectionstatechange=async function(e){
log('onSignalingServerMediaMediatorOfferFunc.myRTCMediaMediatorConnections['+id+']['+hash+'].onconnectionstatechange('+This.myRTCMediaMediatorConnections[id][hash].connectionState+')',10,true)
switch(This.myRTCMediaMediatorConnections[id][hash].connectionState){
case "failed":
This.disconnectMeFromMediatorConnection(targetId,logicGroupName,streamerId,streamerHash,id,hash)
break
case "closed":
This.disconnectMeFromMediatorConnection(targetId,logicGroupName,streamerId,streamerHash,id,hash)
break
case "disconnected":
if(await This.confirmPeerDisconnection(This.myRTCMediaMediatorConnections[id][hash]))This.disconnectMeFromConnection(targetId,logicGroupName,streamerId,streamerHash,id,hash)
break
}
log('onSignalingServerMediaMediatorOfferFunc.myRTCMediaMediatorConnections['+id+']['+hash+'].onconnectionstatechange',10,false)
}
this.confirmPeerDisconnection=async function(connectionObject){
log('confirmPeerDisconnection',10,true)
var b1=await this.confirmPeerDisconnectionFunc(connectionObject);
await new Promise(resolve=>setTimeout(resolve,2000));
var b2=await this.confirmPeerDisconnectionFunc(connectionObject);
log('confirmPeerDisconnection=>'+(b2-b1),10,false)
if(b2-b1>0)return false
return true;
}
this.confirmPeerDisconnectionFunc=async function(connectionObject){
var b=0
await connectionObject.getStats(null).then(function(stats){
stats.forEach((report)=>{if(report.type=='transport')Object.keys(report).forEach((statName)=>{if(statName==='bytesReceived')b=parseInt(report[statName])})})
})
return b
}
b2-b1 always equals 0 or less than 0. Can anyone give me an advise why RTCPeerConnection.onconnectionstatechange fires and how I can get rid of this bug.
Any help appriciated!

$refs are null after route change

I have a keyboard navigation system. When you press ArrowUp or ArrowDown, an event is emitted FROM app.js (best place I found to listen to these keypresses since they need to be system-wide) TO the mounted() in the component.
The Event.$on() INSIDE the mounted() part of the component then calls a function that uses $refs to identify the currently selected item and, when ENTER is pressed, show it's modal.
app.js code (listen to the keypresses):
else if (event.key === 'ArrowUp' || event.key === 'ArrowDown' || event.key === 'Enter') {
event.preventDefault()
switch (this.$router.currentRoute.path) {
case "/pedidos":
Event.$emit('navegarSetasPedidos', event.key)
break;
case "/clientes":
Event.$emit('navegarSetasClientes', event.key)
break;
}
}
mounted() section of the component in question:
mounted() {
Event.$on('navegarSetasPedidos', (key) => {this.navegarSetas(key)})
}
function responsible for the navigation (sorry for bad formating, haven't figured how stackoverflow's codeblock thing works yet):
navegarSetas(key) {
if (this.navegacaoSetasAtiva == false) {
this.navegacaoSetasAtiva = true
this.navegacaoAtual = 0
} else if (this.modalAtivado == false && this.navegacaoSetasAtiva == true) {
if (key == 'ArrowDown' && this.navegacaoAtual < this.pedidos.length - 1) {
this.navegacaoAtual++
let elementoSelecionado = this.$refs['pedido'+this.navegacaoAtual][0].$el
let boundaries = elementoSelecionado.getBoundingClientRect()
if (boundaries.top < 0 || boundaries.top > (window.innerHeight || document.documentElement.clientHeight)){
elementoSelecionado.scrollIntoView({behavior: 'smooth'})
}
} else if (key == 'ArrowUp' && this.navegacaoAtual <= this.pedidos.length && this.navegacaoAtual > 0) {
this.navegacaoAtual--
let elementoSelecionado = this.$refs['pedido'+this.navegacaoAtual][0].$el
let boundaries = elementoSelecionado.getBoundingClientRect()
if (boundaries.top < 0 || boundaries.top > (window.innerHeight || document.documentElement.clientHeight)){
elementoSelecionado.scrollIntoView({behavior: 'smooth'})
}
} else if (key == 'Enter') {
let pedidoSelecionado = this.pedidos[this.navegacaoAtual].id
Event.$emit('changeShow', pedidoSelecionado)
}
}
This works very well the first time it is acessed. The problem is, if I change the current route to show another component and then return to the previous component, I get a lot of "this.$refs['pedido'+this.navegacaoAtual][0].$el is undefined" errors, but the system still works normally, albeit erratically.
The funny thing is: if I console log "this.$refs['pedido'+this.navegacaoAtual][0].$el is undefined", I'll get an EMPTY log before the errors, then ANOTHER one right below it, this time, not empty.
Everywhere else I've searched this says that the problem is due to how Vue re-renders things, and that I'm calling this event BEFORE it's rendered, which shouldn't be possible since I'm calling it inside mounted().
Any help is greatly appreciated, thank you!
Turns out, after a LOT of searching, the Event.$on event setters also work as the normal JavaScript ones (which makes a lot of sense now that I'm thinking about it)—meaning that you have to destroy them whenever your component is unmounted (aka Destroyed).
Even though VUE Dev Tools was picking only one event after the re-route, it was still firing two (seen through console.log() returning one empty value, a bunch of errors, and another value with filled array AFTER the errors).
The solution to this was simply adding Event.$off('eventName') on the destroyed() function of the component.

Checking canDrop() result

I have a type of dragSource, let's call it Card, and a dropTarget Stacks. There are many stacks, but each card can't be dropped to all of them. So in the Stack's canDrop method I get the Card being dragged, run some comparisons and return whether that card can be dropped.
So, all good until here. When a user tries dropping a Card to a wrong Stack, canDrop returns false and nothing happens.
My question now is, when the drop action fails, I want to display a message like "You can't drop this card here because of reasons". How do I do that using react-dnd? I can't use the result from canDrop, because the drop never happened so it isn't handled? I could move the canDrop logic to the function that moves the card to the desired Stack, but then react-dnd would only be specifying that a Card can be dropped on a Stack and all the logic for if a card can be dropped on a certain stack would be handled by my code.
Is this correct? Is there any other way of doing this using the library I'm not seeing? What would be a good approach for this?
You can access the status of the finished drag (whether successful or not) via the DragSourceMonitor. You will still need to get clever/dirty over how to pass different reasons, I'm pretty sure hover is called even if cant drop, so could cache a reason when you drag over an incompatible drop target, then clear it when drag is complete...
const reasons = '';
const dragSourceSpec = {
//...
endDrag: (props, monitor, component) => {
if (!monitor.didDrop()) {
console.warn('Drop could not be handled, because of: ', reasons)
} else {
console.info('Drop was handled, and returned: `, monitor.getDropResult())
}
// reset reason for next drag
reasons = ''
}
}
const dropTargetSpec = {
//...
hover: (props, monitor, component) => {
reasons = monitor.canDrop() ? '' : 'Stack is full'
}
}

How to wait for Location Alert ( which is system alert) to show?

I figured out how to dismiss System alert, but I am not able to wait for it to show , since app doesn't see System Alerts. I tried to debug with app.debugDescription and app.alerts.count but no luck.
You should use addUIInterruptionMonitor as #Oletha wrote.
The tricky part here is that system alert buttons don't use Accessibility Identifiers so you have to search for text to tap them. This text is translated to the language you're running your simulator/device, which can be hard if you want to run the test for several languages beside English.
You could use AutoMate framework to simplify this. Here you have an example how to deal with system alerts using AutoMate:
func locationWhenInUse() {
let token = addUIInterruptionMonitor(withDescription: "Location") { (alert) -> Bool in
guard let locationAlert = LocationWhenInUseAlert(element: alert) else {
XCTFail("Cannot create LocationWhenInUseAlert object")
return false
}
locationAlert.allowElement.tap()
return true
}
// Interruption won't happen without some kind of action.
app.tap()
// Wait for given element to appear
wait(forVisibilityOf: locationPage.requestLabel)
removeUIInterruptionMonitor(token)
}
In the example above the locationAlert.allowElement.tap() is possible because AutoMate can handle any language supported by iOS Simulator.
For more examples on how to deal with system alerts using AutoMate please look into: PermissionsTests.swift
Use addUIInterruptionMonitor:withDescription:handler: to register an interruption monitor. To 'wait' for the system alert to appear, use the handler to set a variable when it has been dealt with, and execute a benign interaction with the app when you want to wait for the alert.
You must continue to interact with the app while you are waiting, as interactions are what trigger interruption monitors.
class MyTests: XCTestCase {
let app = XCUIApplication()
func testLocationAlertAppears() {
var hasDismissedLocationAlert = false
let monitor = addUIInterruptionMonitor(withDescription: "LocationPermissions") { (alert) in
// Check this alert is the location alert
let location = NSPredicate(format: "label CONTAINS 'Location'")
if alert.staticTexts.element(matching: location).exists {
// Dismiss the alert
alert.buttons["Allow"].tap()
hasDismissedLocationAlert = true
return true
}
return false
}
// Wait for location alert to be dismissed
var i = 0
while !hasDismissedLocationAlert && i < 20 {
// Do some benign interaction
app.tap()
i += 1
}
// Clean up
removeUIInterruptionMonitor(monitor)
// Check location alert was dismissed
XCTAssertTrue(hasDismissedLocationAlert)
}
}

Play and pause functions works only once

I'm viewing the live streams using the flash player. while i'm doing that i have tried to play and pause the streams using the following function but it is only works for only one click. if i'm re-clicking it does not shows any changes. If you realize my problem. please suggest me.
function testPause(event:MouseEvent) {
nsPlay.pause();
}
function testPlay(event:MouseEvent) {
if(!bolLoaded) {
nsPlay.play(streamValue);
bolLoaded = true;
} else {
nsPlay.resume();
}
}
Make Boolean variable value FALSE in pause state.
bolLoaded = false;