Script to automaticly include Simple Logging cards into your flows
Use this script to automaticly add logging cards to your flows: Currently, it adds logging to each flowcard’s error catch in advanced flows.
Execute this in the WebApi Playground.
Note: Work in progress.
const version = '1.0.1';
const excludeBrokenFlows = true;
const automaterLocation = 'BottomLeft'; //TopLeft, LeftTop, BottomLeft
const automaterOffsetY = 0;
const automaterOffsetX = 0;
const automaterAutoMoveCards = true;
const errorSeverity = 3, triggerSeverity = 6, conditionSeverity = 6, actionSeverity = 6, facility = 16;
const positionErrorCards = { y: -3, x: 1 }; //Number of blocks relative from the card to which it is appended.
const createErrorCards = true; // = true, automaticly create logging card for each error in the selected (or all) flows.
const deleteErrorCards = false; !createErrorCards; // = true, delete all automaticly created logging card from the selected (or all) flows.
const positionTriggerCards = { y: -3, x: 1 }; //Number of blocks relative from the card to which it is appended.
const createTriggerCards = true; // = true, automaticly create logging card for each error in the selected (or all) flows.
const deleteTriggerCards = false; !createTriggerCards; // = true, delete all automaticly created logging card from the selected (or all) flows.
const positionConditionCards = { y: -3, x: 1 }; //Number of blocks relative from the card to which it is appended.
const createConditionCards = true; // = true, automaticly create logging card for each error in the selected (or all) flows.
const deleteConditionCards = false; !createConditionCards; // = true, delete all automaticly created logging card from the selected (or all) flows.
const positionActionCards = { y: -3, x: 1 }; //Number of blocks relative from the card to which it is appended.
const createActionCards = true; // = true, automaticly create logging card for each error in the selected (or all) flows.
const deleteActionCards = false; !createActionCards; // = true, delete all automaticly created logging card from the selected (or all) flows.
let flowNames = ['AddLogCards (Test)', 'AddLogCards (Test2)']; // Use this line for selected flows
//let flowNames; // Use this line for all flows
/* Automatic const, leave it be */
const createAutomaterCard = 'homey:app:nl.nielsdeklerk.log:Automater'; // Zet to null for no card (required as of now)
const automaterUri = createAutomaterCard.substring(0, createAutomaterCard.lastIndexOf(':'));
const automaterId = createAutomaterCard.substring(createAutomaterCard.lastIndexOf(':') + 1);
const automaterMoveCardsY = _.max([positionTriggerCards.y, positionErrorCards.y]) * 20 * -1;
const automaterTopMargin = 160;
console.log(automaterMoveCardsY);
async function run() {
let APIv3 = Number.parseInt((await Homey.system.getInfo()).homeyVersion.split('.')) >= 10;
let afs = await Homey.flow.getAdvancedFlows();
afs = _.toArray(afs);
if (excludeBrokenFlows) afs = _.filter(afs, x => !x.broken);
if (flowNames) afs = _.filter(afs, x => flowNames.indexOf(x.name) > -1);
console.log(afs[1]);
for (let i = 0; i < afs.length; i++) {
let af = afs[i];
let logCard;
let automaterCard = _.find(af.cards, x => checkId(x, automaterUri, automaterId));
let automaterArgs = {
af, position: { location: automaterLocation, offsetY: automaterOffsetY, offsetX: automaterOffsetX, autoMoveCards: automaterAutoMoveCards },
errorSeverity, triggerSeverity, conditionSeverity, actionSeverity, facility, createErrorCards, createTriggerCards, createConditionCards, createActionCards
};
if (automaterCard)
automaterCard.args.id = af.id;
if (automaterCard && automaterCard.args.update) {
automaterArgs.card = automaterCard;
updateAutomaterCard(automaterArgs);
}
if (!automaterCard) {
automaterCard = getNewAutomaterCard(automaterArgs);
automaterArgs.card = automaterCard;
af.cards[uuid()] = automaterCard;
}
for (const cardKey in af.cards) {
if (Object.hasOwnProperty.call(af.cards, cardKey)) {
//const af.cards[cardKey] = af.cards[cardKey];
if (checkId(af.cards[cardKey], automaterUri, automaterId)) continue;
if (!af.cards[cardKey].id) continue;
if (automaterCard.args.errorCards===false) {
if (checkId(af.cards[cardKey], 'homey:app:nl.nielsdeklerk.log', 'Automater_log') && af.cards[cardKey].args.auto_created == true) {
delete af.cards[cardKey];
//continue;
}
if (af.cards[cardKey].outputError) af.cards[cardKey].outputError = _.filter(af.cards[cardKey].outputError, x => af.cards[x]);
//continue;
}
if (automaterCard.args.errorCards===true && !checkId(af.cards[cardKey], 'homey:app:nl.nielsdeklerk.log') && af.cards[cardKey].type != 'trigger' && (!af.cards[cardKey].outputError || !af.cards[cardKey].outputError.length || !(logCard = _.find(af.cards[cardKey].outputError, x => af.cards[x] && af.cards[x].id && checkId(af.cards[x], 'homey:app:nl.nielsdeklerk.log'))))) {
let uid = uuid();
let newCard = getNewCard({ card: af.cards[cardKey], cardKey, af, position: positionErrorCards, automaterCard, type: 'error', severity: errorSeverity });
if (!af.cards[cardKey].outputError) af.cards[cardKey].outputError = [];
af.cards[cardKey].outputError.push(uid);
let l = {};
l[uid] = newCard;
af.cards = _.merge(l, af.cards);
}
if (!checkId(af.cards[cardKey], 'homey:app:nl.nielsdeklerk.log') && af.cards[cardKey].type === 'trigger') {
if ((!af.cards[cardKey].outputSuccess || !af.cards[cardKey].outputSuccess.length || !(logCard = _.find(af.cards[cardKey].outputSuccess, x => af.cards[x] && af.cards[x].id && checkId(af.cards[x], 'homey:app:nl.nielsdeklerk.log')))) && automaterCard.args.triggerCards===true) {
let uid = uuid();
let newCard = getNewCard({ card: af.cards[cardKey], cardKey, af, position: positionTriggerCards, automaterCard, type: 'trigger', severity: triggerSeverity });
if (!af.cards[cardKey].outputSuccess) af.cards[cardKey].outputSuccess = [];
af.cards[cardKey].outputSuccess.push(uid);
let l = {};
l[uid] = newCard;
af.cards = _.merge(l, af.cards);
} else if (logCard && automaterCard.args.updateCards===true) updateLogCard({ card: logCard, af, automaterCard, severity: automaterCard.args.triggerSeverity, facility: automaterCard.args.facility });
}
if (!checkId(af.cards[cardKey], 'homey:app:nl.nielsdeklerk.log') && af.cards[cardKey].type === 'condition') {
let errorCard = _.find(af.cards[cardKey].outputError, x => af.cards[x] && af.cards[x].id && checkId(af.cards[x], 'homey:app:nl.nielsdeklerk.log'));
if (errorCard) errorCard = af.cards[errorCard];
if ((!af.cards[cardKey].outputTrue || !af.cards[cardKey].outputTrue.length || !(logCard = _.find(af.cards[cardKey].outputTrue, x => af.cards[x] && af.cards[x].id && checkId(af.cards[x], 'homey:app:nl.nielsdeklerk.log')))) && automaterCard.args.conditionCards===true) {
let uid = uuid();
let newCard = getNewCard({ card: af.cards[cardKey], cardKey, af, position: positionConditionCards, automaterCard, type: 'condition', value: true, id: errorCard.args.id, severity: conditionSeverity });
if (!af.cards[cardKey].outputTrue) af.cards[cardKey].outputTrue = [];
af.cards[cardKey].outputTrue.push(uid);
let l = {};
l[uid] = newCard;
af.cards = _.merge(l, af.cards);
} else if (logCard && automaterCard.args.updateCards===true) updateLogCard({ card: logCard, af, automaterCard, severity: automaterCard.args.conditionSeverity, facility: automaterCard.args.facility });
logCard = undefined;
if ((!af.cards[cardKey].outputFalse || !af.cards[cardKey].outputFalse.length || !(logCard = _.find(af.cards[cardKey].outputFalse, x => af.cards[x] && af.cards[x].id && checkId(af.cards[x], 'homey:app:nl.nielsdeklerk.log')))) && automaterCard.args.conditionCards===true) {
let uid = uuid();
let newCard = getNewCard({ card: af.cards[cardKey], cardKey, af, position: positionConditionCards, automaterCard, type: 'condition', value: false, id: errorCard.args.id, severity: conditionSeverity });
if (!af.cards[cardKey].outputFalse) af.cards[cardKey].outputFalse = [];
af.cards[cardKey].outputFalse.push(uid);
let l = {};
l[uid] = newCard;
af.cards = _.merge(l, af.cards);
} else if (logCard && automaterCard.args.updateCards===true) updateLogCard({ card: logCard, af, automaterCard, severity: automaterCard.args.conditionSeverity, facility: automaterCard.args.facility });
}
if (!checkId(af.cards[cardKey], 'homey:app:nl.nielsdeklerk.log') && af.cards[cardKey].type === 'action') {
if ((!af.cards[cardKey].outputSuccess || !af.cards[cardKey].outputSuccess.length || !(logCard = _.find(af.cards[cardKey].outputSuccess, x => af.cards[x] && af.cards[x].id && checkId(af.cards[x], 'homey:app:nl.nielsdeklerk.log')))) && automaterCard.args.actionCards===true) {
let errorCard = _.find(af.cards[cardKey].outputError, x => af.cards[x] && af.cards[x].id && checkId(af.cards[x], 'homey:app:nl.nielsdeklerk.log'));
if (errorCard) errorCard = af.cards[errorCard];
let uid = uuid();
let newCard = getNewCard({ card: af.cards[cardKey], cardKey, af, position: positionActionCards, automaterCard, type: 'action', id: errorCard.args.id, severity: actionSeverity });
if (!af.cards[cardKey].outputSuccess) af.cards[cardKey].outputSuccess = [];
af.cards[cardKey].outputSuccess.push(uid);
let l = {};
l[uid] = newCard;
af.cards = _.merge(l, af.cards);
} else if (logCard && automaterCard.args.updateCards===true) updateLogCard({ card: logCard, af, automaterCard, severity: automaterCard.args.actionSeverity, facility: automaterCard.args.facility });
}
}
}
try {
let id = af.id;
af = {
//id: af.id,
name: af.name,
cards: af.cards
};
//console.log(JSON.stringify(af));
afs[i] = af;
await Homey.flow.updateAdvancedFlow({ id, advancedflow: af });
} catch (ex) {
console.log(ex);
}
}
return afs;
//log(JSON.stringify(afs));
function uuid() {
var d = new Date().getTime();
var d2 = ((typeof performance !== 'undefined') && performance.now && (performance.now() * 1000)) || 0;
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16;
if (d > 0) {
r = (d + r) % 16 | 0;
d = Math.floor(d / 16);
} else {
r = (d2 + r) % 16 | 0;
d2 = Math.floor(d2 / 16);
}
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
}
function checkId(card, uri, id) {
return id ?
(APIv3 ? card.id == uri + ':' + id : card.ownerUri == uri && card.id == id)
:
(APIv3 ? card.id.startsWith(uri + ':') : card.ownerUri == uri)
;
}
function getNewCard({ card, cardKey, af, position: { x, y }, automaterCard, type, value, id, severity }) {
let r = {};
if (APIv3) {
r.ownerUri = "homey:app:nl.nielsdeklerk.log";
r.id = 'homey:app:nl.nielsdeklerk.log:Automater_log';
} else {
r.ownerUri = "homey:app:nl.nielsdeklerk.log";
r.id = "Automater_log";
}
if (!id) automaterCard.args[card.type + 'Index']++;
id = id ? id : (card.type.substring(0, 1).toUpperCase() + automaterCard.args[card.type + 'Index']);
let log = id;
switch (type) {
case "error": log += ": [[" + (APIv3 ? 'card' : card.type) + "::" + cardKey + "::error]]"; break;
case "trigger": log += ': Triggered'; break;
case "condition": log += ': ' + value; break;
case "action": log += ': Executed'; break;
}
r.args = {
id,
log,
group: af.name,
severity: severity || "6",
facility: automaterCard.args.facility || '16',
auto_created: true
};
r.type = "action";
x = card.x + (20 * x);
r.x = x > 0 ? x : 0;
y = card.y + (20 * y);
r.y = y > 0 ? y : 0;
return r;
}
function getNewAutomaterCard({ af, errorSeverity, triggerSeverity, conditionSeverity, actionSeverity, facility, position: { location, offsetX, offsetY, autoMoveCards }, createErrorCards, createTriggerCards, createConditionCards, createActionCards }) {
let r = {};
const uri = createAutomaterCard.substring(0, createAutomaterCard.lastIndexOf(':'));
const id = createAutomaterCard.substring(createAutomaterCard.lastIndexOf(':') + 1);
if (APIv3) {
r.ownerUri = uri;
r.id = uri + ':' + id;
} else {
r.ownerUri = uri;
r.id = id;
}
r.args = {
//id:af.id,
group: af.name,
triggerIndex: 0,
conditionIndex: 0,
actionIndex: 0,
update: true,
updateCards: true,
errorCards: createErrorCards,
triggerCards: createTriggerCards,
conditionCards: createConditionCards,
actionCards: createActionCards,
//autoMoveCards,
// errorSeverity:3,
// conditionSeverity:6,
// actionSeverity:6,
// facility: "16",
auto_created: true
};
r.type = "action";
let x = 0, y = 0;
switch (location) {
case "LeftTop":
x = 0 + (offsetX > 0 ? (offsetX) : 0);
y = 0 + (offsetY > 0 ? (offsetY) : 0);
_.each(af.cards, x => { x.x += 400; x.y += automaterMoveCardsY });
break;
case "TopLeft":
x = 0 + (offsetX > 0 ? (offsetX) : 0);
y = 0 + (offsetY > 0 ? (offsetY) : 0);
_.each(af.cards, x => x.y += automaterTopMargin + automaterMoveCardsY);
break;
case "BottomLeft":
x = 0 + offsetX > 0 ? (offsetX || 0) : 0;
let max = _.maxBy(_.toArray(af.cards), x => x.y);
max = max ? max.y + automaterTopMargin + automaterMoveCardsY : 0;
y = max + (offsetY > 0 ? (offsetY) : 0);
_.each(af.cards, x => { x.y += automaterMoveCardsY });
break;
}
r.x = x > 0 ? x : 0;
r.y = y > 0 ? y : 0;
r.args.errorSeverity = errorSeverity ? errorSeverity.toString() : '';
r.args.conditionSeverity = conditionSeverity ? conditionSeverity.toString() : '';
r.args.actionSeverity = actionSeverity ? actionSeverity.toString() : '';
r.args.triggerSeverity = triggerSeverity ? triggerSeverity.toString() : '';
r.args.facility = facility ? facility.toString() : '';
updateAutomaterCard({ card: r, af, errorSeverity, triggerSeverity, conditionSeverity, actionSeverity, facility })
// x= card.x + (20 * x);
// r.x= x>0?x:0;
// y = card.y + (20 * y);
// r.y= y>0?y:0;
return r;
}
function updateAutomaterCard({ card, af, errorSeverity, triggerSeverity, conditionSeverity, actionSeverity, facility, createErrorCards, createTriggerCards, createConditionCards, createActionCards }) {
card.args.id = af.id;
card.args.group = af.name;
card.args.errorCards = createErrorCards;
card.args.triggerCards = createTriggerCards;
card.args.conditionCards = createConditionCards;
card.args.actionCards = createActionCards;
card.args.errorSeverity = errorSeverity ? errorSeverity.toString() : '';
card.args.conditionSeverity = conditionSeverity ? conditionSeverity.toString() : '';
card.args.actionSeverity = actionSeverity ? actionSeverity.toString() : '';
card.args.triggerSeverity = triggerSeverity ? triggerSeverity.toString() : '';
card.args.facility = facility ? facility.toString() : '';
}
function updateLogCard({ card, af, severity, facility, automaterCard }) {
af.cards[card].args.group = automaterCard.args.group;
af.cards[card].args.severity = severity ? severity.toString() : '';
af.cards[card].args.facility = facility ? facility.toString() : '';
}
}
run();