How to use Enrichment Nodes in Thingsboard,
I tried Customer, Device, Related Attributes Node but couldnt able to get that data on metadata. Cany you help me to figure it out.
Screenshot:
Rule Node:
Related Attribute details:
Transform Script:
I got my device attributes using originator attributes Enrichment Node in ThingsBoard
thank you for answer, I have successfully fetched server attributes of my device. Here are some materials how I did it for someone in the future:
Images:
Part of rule chain
Enrichment - originator attributes
Script testing: (stackoverflow is trowing me some errors for not properly formatting code, so go on this): https://i.stack.imgur.com/85Cwi.png and https://i.stack.imgur.com/na1LK.png
Code from script (comments are in Croatian language if you wish to translate them):
//metadata.ImpFor_delta_hour je povjesna varijabla
//msg.ImpFor_delta_hour je upravo izracunati satna delta od ImpFor-a
if (typeof metadata.ImpFor_delta_5 !== 'undefined' && typeof metadata.ss_delta_ImpFor_min !== 'undefined' && typeof metadata.ss_delta_ImpFor_max !== 'undefined') { //ako nam nije dostavljen povjesni podatak ili nisu definirane granice
//ImpFor_delta_hour dolazi u obliku \"17\" (tocno s tim znakovima, nisam nista dodao)
var HIST_ImpFor = metadata.ImpFor_delta_5; //mozda nepotrebno, ali lakse je za raditi s varijablom
HIST_ImpFor = HIST_ImpFor.replace(/\"/g, ''); //micemo visak oko broja
HIST_ImpFor = parseInt(HIST_ImpFor); //string->integer
//po povjesnoj vrijednosti se stvaraju granice
var histDGranica = HIST_ImpFor * (metadata.ss_delta_ImpFor_min/100); //granice se definiraju za svaki node individualno u njihovim server atributes
var histGGranica = HIST_ImpFor * (metadata.ss_delta_ImpFor_max/100); //granice su deinirane kao % u server atributes, ali nam ovdje treba /100 (55%/100=0.55)
if (msg.ImpFor_delta_5 > histDGranica && msg.ImpFor_delta_5 < histGGranica){ //da li je nova delta unutar granica
return true;
}else{
return false;
}
}else{
return true; //ako nemamo povjesnog podatka ne mozemo procjeniti da li je ili nije unutar granica pa nema smisla dizati alarm
}
//throw new Error(HIST_ImpFor); //ako zelis isprintati neku variablu u error popup
Related
I got a sheet with merged cells and in those merged cells, a script write its results.
When I copy this result in the merged cells, it gave me multiple spaces at the end.
Like : Result #1________ (« _ » represent invisible space)
When I put the same result in a normal cell (not merged), it doesn’t put any space at the end.
Result #1
I tried multiple cell format (Center aligned, left aligned, etc.) but nothing changed.
Do you have any idea why ?
Thanks !
EDIT : add script
Script
function Devise() {
const sheetName = "Missions";
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
var Devise = "";
var NombreMission = "";
var NomOperateurs = "";
if(sheet.getRange("H2").getValue()=="") { // Si la mission 7 est vide
NombreMission = 6; // On compte seulement 6 missions
} else {
NombreMission = 7; // Sinon on compte 7 missions
}
for (i = 1; i < NombreMission+1; i++) { // Boucle FOR pour NombreMission missions
if(sheet.getRange(2,i+1).getValue()=="") { continue; } // Si la mission est vide, on la passe
Devise = Devise + i + "/";
l = 0; // Variable pour indiquer "Rien" si personne à placer dans la mission
NomOperateurs = ""; // Reset les noms pour la mission d'après
for (j = 1; j < 27+1; j++) { // Boucle FOR pour tous les opérateurs
if(sheet.getRange(j+2,i+1).getFontWeight() == 'bold') { // Vérifie si la case est en gras
/*if(i!=NombreMission) { // Tant qu'il ne s'agit pas de la dernière mission ...
Devise = Devise + sheet.getRange(j+2,1).getValue() + " "; // ... on affiche les opérateurs
}*/
NomOperateurs = NomOperateurs + sheet.getRange(j+2,1).getValue() + " ";
l = l + 1; // On compte les opérateurs
}
} // Fin Boucle FOR opérateurs
if (l==24) { // S'il y a tous les operateurs sur une mission...
Devise = Devise + "ALL OPs! " // ... On affiche "All Op!"
} else if (i==NombreMission && l!=0) { // Sinon s'il s'agit de la dernière mission et qu'il reste des opérateurs à placer...
Devise = Devise + "Autres + Epic "; // ... On indique qu'il s'agit du reste et des épiques
} else if (l==0) { // Sinon s'il n'y a aucun opérateurs à placer...
Devise = Devise + "RIEN " // ... On indique "RIEN"
} else { // Sinon ...
Devise = Devise + NomOperateurs; // ... On affiche les opérateurs
}
} // FIN BOUCLE FOR NombreMission
if(NombreMission==6 && Devise!="") { Devise = Devise + "7/!NOTHING!";}
sheet.getRange("K13").setValue(Devise);
}
Your problem is related to the data you copied and the way that you copied it as pasting text in merged cells doesn't create any new lines.
Also, an important thing to keep in mind is that CTRL+ENTER creates the mentioned space also known as a line break.
So, for example, if this cell contains the text Text + line break:
And the text from the above cell is copied and pasted into a merged cell it will look like this - which is the same outcome as the one that you have mentioned:
But if you paste the same text to a simple cell, it will look like this:
This is essentially because the line break will signify the start of a new cell.
For example, this cell contains this text with line breaks:
After the text is copied and pasted into a different cell, this is how it will actually be pasted as:
In order to solve your issue, I suggest you to copy only the text needed and if possible to avoid using any line breaks.
Reference
Edit and Format a Spreadsheet.
Encountering the same issue.
I have a merged cell with text. If I select the cell and paste it into notepad, It includes quite a lot of white space.
I've checked and if the merged cell spans two rows, the white space includes a line break.
If the merged cell spans one row but two columns, the white space does not include a line break.
If I have a single cell and have it take its value from the mered cell "=A1", the text does not include the white space.
So the addition of the whitespace is definitely the result of having a merged cell.
I am trying to modify the accumulator generator example to load two accesses at once, for example to load two indices from one array. All I changed is that when the first memory response comes in, I increment a counter and send out another. But I get a cache exception. My code for the accelerator is below. It only has a few changes from the accumulator.
What’s confusing too me is that the first access works and I get the data, and for now, I’m using the same address with the second access. So why wouldn’t this work?
val regfile = Mem(4, UInt(width = 16.W))
val busy = Reg(init = Vec.fill(4){Bool(false)})
val cmd = Queue(io.cmd)
val funct = cmd.bits.inst.funct
val addr = cmd.bits.rs2(log2Up(4)-1,0)
val doLoad = funct === UInt(0)
val doRead = funct === UInt(1)
val doWrite = funct === UInt(2)
val doAccum = funct === UInt(3)
val memRespTag = io.mem.resp.bits.tag
// datapath
val addend = cmd.bits.rs1
val accum = regfile(addr)
val wdata = Mux(doWrite, addend, accum + addend)
val counter = RegInit(0.U)
when (cmd.fire() && (doWrite || doAccum)) {
regfile(addr) := wdata
}
when (io.mem.resp.valid) {
regfile(memRespTag) := io.mem.resp.bits.data
busy(memRespTag) := Bool(false)
when(counter === 0.U) {
counter := 1.U
}
}
// control
when (io.mem.req.fire()) {
busy(counter) := Bool(true)
}
val doResp = cmd.bits.inst.xd
val stallReg = busy(counter)
val stallLoad = doLoad && !io.mem.req.ready
val stallResp = doResp && !io.resp.ready
cmd.ready := !stallReg && !stallLoad && !stallResp // command resolved if no stalls AND not issuing a load that will need a request
// PROC RESPONSE INTERFACE
io.resp.valid := cmd.valid && doResp && !stallReg && !stallLoad
// valid response if valid command, need a response, and no stalls
io.resp.bits.rd := cmd.bits.inst.rd
// Must respond with the appropriate tag or undefined behavior
io.resp.bits.data := accum
// Semantics is to always send out prior accumulator register value
io.busy := cmd.valid || busy.reduce(_||_)
// Be busy when have pending memory requests or committed possibility of pending requests
io.interrupt := Bool(false)
// Set this true to trigger an interrupt on the processor (please refer to supervisor documentation)
io.mem.req.valid := ((cmd.valid && doLoad) || counter === 1.U ) && !stallReg && !stallResp
io.mem.req.bits.addr := addend
io.mem.req.bits.tag := addr
io.mem.req.bits.cmd := M_XRD // perform a load (M_XWR for stores)
io.mem.req.bits.size := log2Ceil(8).U
io.mem.req.bits.signed := Bool(false)
io.mem.req.bits.data := Bits(0) // we're not performing any stores...
io.mem.req.bits.phys := Bool(false)
I managed to read multiple locations from io.mem interface but still struggling with multiple writes.
Initially, i also faced same exception because i provided invalid memory address (no memory was existed with that address) at the time of io.mem request is triggered.
Here, in your case after toggling counter to value 1 from 0. It remains high. So there is no control from cmd.valid. In this case cmd.valid is important as value (addend) assigned to io.mem.req.bits.addr signal is only valid when cmd.valid is high. You can make interface independent of cmd.valid.You have to modify interface accordingly.
So, conclusion is,Sample valid address for io.mem.req interface.From my experience you can read as many locations as you want with single custom command.
Thanks & Regards,
Sanket,
The title may be a bit confusing but basically this is the problem: I am using Jena and a Pellet reasoner to produce property literals from a resource called Patient_Doug. The triple looks like this:
Patient_Doug-> hasSuggestion-> Literal inferred suggestion.
The problem is that the Protege Pellet reasoner comes up with three suggestions for Doug, because Doug is in a pretty bad way in hospital. The Protege reasoner suggests that Doug needs a Hi-Lo bed, an RF ID band and a bed closer to the nurse's station. Unfortunatly, in Jena, I can only get Hi-lo bed to print. Only one of 3 literals.
Here is some of the code.
OntModel model = ModelFactory.createOntologyModel( PelletReasonerFactory.THE_SPEC );
String ns = "http://altervista.org/owl/unit.owl#";
String inputFile = "c:\\jena\\acuity.owl";
InputStream in = FileManager.get().open(inputFile);
if (in == null) {
throw new IllegalArgumentException("File: " + inputFile + " not found");
}
model.read(in,"");
model.prepare();
//inf and reasoner wont run unless i use hp libraries!
//asserted data properties
Individual ind = model.getIndividual(ns+"Patient_Doug");
OntProperty abcValue = model.getOntProperty("http://example.org/hasABCValue");
//inferred data properties
OntProperty suggestion = model.getOntProperty(ns+"hasSuggestion");
//print asserted data properties
System.out.println("Properties for patient "+ind.getLocalName().toString());
System.out.println( abcValue.getLocalName()+"= "+ind.getPropertyValue(abcValue).asLiteral().getInt());
//print inferenced data properties
StmtIterator it = ind.listProperties(suggestion);
//this iterator only prints one suggestion in an infinite loop
while (it.hasNext()) {
System.out.println("A posible suggestion= "+ind.getPropertyValue(suggestion).asLiteral().getString());
}
}
The code works fine but the iterator at the end only prints only one subggestion in an infinite loop.
I would be grateful for any suggestions.
Thanks.
This code works to iterate and print the many inferred hasSuggestions. The hasSuggestion SWRL rules are in the OWL ontology
OntModel model = ModelFactory.createOntologyModel( PelletReasonerFactory.THE_SPEC );
String ns = "http://altervista.org/owl/unit.owl#";
String inputFile = "c:\\jena\\acuity.owl";
InputStream in = FileManager.get().open(inputFile);
if (in == null) {
throw new IllegalArgumentException("File: " + inputFile + " not found");
}
model.read(in,"");
model.prepare();
//inf and reasoner wont run unless i use hp libraries!
//asserted data properties
Individual ind = model.getIndividual(ns+"Patient_Doug");
OntProperty abcValue = model.getOntProperty("http://example.org/hasABCValue");
//inferred data properties
OntProperty suggestion = model.getOntProperty(ns+"hasSuggestion");
//print asserted data properties
System.out.println("Properties for patient "+ind.getLocalName().toString());
System.out.println( abcValue.getLocalName()+"= "+ind.getPropertyValue(abcValue).asLiteral().getInt());
for (StmtIterator j = ind.listProperties(suggestion); j.hasNext(); ) {
Statement s = j.next();
//System.out.println( " " + s.getPredicate().getLocalName() + " -> " );
System.out.println( "A possible suggestion... " + s.getLiteral().getLexicalForm());
}
I am using a combination of Google Sheets, Google Presentation, and Zapier to automate my companies business card design workflow. My template looks like this:
{Full Name}}
{{Job Title}}
{{School Site}}
{{Street Address}}
Broken Arrow, Oklahoma {{Zip Code}}
{{Office Number}}{{Print Cell/Fax}}
{{Email}}
{{Print Cell/Fax}} is populated by a javascript step in Zapier that detects whether the submitter included their cell and fax numbers(These are optional)
and outputs a single variable. This script looks like this:
var cell = inputData.cell
var fax = inputData.fax
var cellFax
if (cell) {
console.log('C: ', cell);
cell='C: '+ inputData.cell;
}else{
console.log('empty');
cell=null;
}
if (fax) {
console.log('F: ', fax);
fax='F: '+ inputData.fax;
}else{
console.log('empty');
fax=null;
}
if (cell!=null && fax!=null) {
cellFax=' / '+cell+fax;
}else if(cell!=null && fax==null) {
cellFax=' / '+cell;
}else if(cell==null && fax!=null) {
cellFax=' / '+fax;
}else{
cellFax=null;
}
output = {cellFax: cellFax};
In the event that both cell and fax variables are empty I need it to populate my template place holder as empty like this:
John Doe
Janitor
International Space Station
555 S. Milkyway St.
Saturn, Vermont 11122
555-259-5555
email#email.com
But what I keep getting this:
John Doe
Janitor
International Space Station
555 S. Milkyway St.
Saturn, Vermont 11122
555-259-5555{{Print Cell/Fax}}
email#email.com
How Do I get it to populate as empty?
try just changing this last part of the javascript from:
}else{
cellFax=null;
}
to:
}else{
cellFax=' ';
}
I'm using ANTLR4 to generate a Lexer for some JavaScript preprocessor (basically it tokenizes a javascript file and extracts every string literal).
I used a grammar originally made for Antlr3, and imported the relevant parts (only the lexer rules) for v4.
I have just one single issue remaining: I don't know how to handle corner cases for RegEx literals, like this:
log(Math.round(v * 100) / 100 + ' msec/sample');
The / 100 + ' msec/ is interpreted as a RegEx literal, because the lexer rule is always active.
What I would like is to incorporate this logic (C# code. I would need JavaScript, but simply I don't know how to adapt it):
/// <summary>
/// Indicates whether regular expression (yields true) or division expression recognition (false) in the lexer is enabled.
/// These are mutual exclusive and the decision which is active in the lexer is based on the previous on channel token.
/// When the previous token can be identified as a possible left operand for a division this results in false, otherwise true.
/// </summary>
private bool AreRegularExpressionsEnabled
{
get
{
if (Last == null)
{
return true;
}
switch (Last.Type)
{
// identifier
case Identifier:
// literals
case NULL:
case TRUE:
case FALSE:
case THIS:
case OctalIntegerLiteral:
case DecimalLiteral:
case HexIntegerLiteral:
case StringLiteral:
// member access ending
case RBRACK:
// function call or nested expression ending
case RPAREN:
return false;
// otherwise OK
default:
return true;
}
}
}
This rule was present in the old grammar as an inline predicate, like this:
RegularExpressionLiteral
: { AreRegularExpressionsEnabled }?=> DIV RegularExpressionFirstChar RegularExpressionChar* DIV IdentifierPart*
;
But I don't know how to use this technique in ANTLR4.
In the ANTLR4 book, there are some suggestions about solving this kind of problems at the parser level (chapter 12.2 - context sensitive lexical problems), but I don't want to use a parser. I want just to extract all the tokens, leave everything untouched except for the string literals, and keep the parsing out of my way.
Any suggestion would be really appreciated, thanks!
I'm posting here the final solution, developed adapting the existing one to the new syntax of ANTLR4, and addressing the differences in JavaScript syntax.
I'm posting just the relevant parts, to give a clue to someone else about a working strategy.
The rule was edited as follows:
RegularExpressionLiteral
: DIV {this.isRegExEnabled()}? RegularExpressionFirstChar RegularExpressionChar* DIV IdentifierPart*
;
The function isRegExEnabled is defined in a #members section on top of the lexer grammar, as follows:
#members {
EcmaScriptLexer.prototype.nextToken = function() {
var result = antlr4.Lexer.prototype.nextToken.call(this, arguments);
if (result.channel !== antlr4.Lexer.HIDDEN) {
this._Last = result;
}
return result;
}
EcmaScriptLexer.prototype.isRegExEnabled = function() {
var la = this._Last ? this._Last.type : null;
return la !== EcmaScriptLexer.Identifier &&
la !== EcmaScriptLexer.NULL &&
la !== EcmaScriptLexer.TRUE &&
la !== EcmaScriptLexer.FALSE &&
la !== EcmaScriptLexer.THIS &&
la !== EcmaScriptLexer.OctalIntegerLiteral &&
la !== EcmaScriptLexer.DecimalLiteral &&
la !== EcmaScriptLexer.HexIntegerLiteral &&
la !== EcmaScriptLexer.StringLiteral &&
la !== EcmaScriptLexer.RBRACK &&
la !== EcmaScriptLexer.RPAREN;
}}
As you can see, two functions are defined, one is an override of lexer's nextToken method, which wraps the existing nextToken and saves the last non-comment-or-whitespace token for reference. Then, the semantic predicate invokes isRegExEnabled checking if the last significative token is compatible with the presence of RegEx literals. If it's not, it returns false.
Thanks to Lucas Trzesniewski for the comment: it pointed me in the right direction, and to Patrick Hulsmeijer for the original work on v3.