Important community news
pimatic-unipi-evok@0.3.3
20200217, V0.3.3 Added support for digital outputs provided with Neuron boards (needs testing) Added automatic build and testing for node 10

read more
Everything that doesn't fit elsewhere
Variable patch as text

Good Morning :)

Can someone explain how I can transfer a variable as text from. Tasker to pimatic ?

I can only patch a variable if it is a number. When I try with text, then I become a error in Tasker an pimatic:
Unexpected parameters

This only works for numbers:

alt text

Regards

read more
You have a cool idea about pimatic?
robotic vacuum ecovacs-deebot ozmo 950 and etc

Yes is ok ;)

I have open a ticket on github
github feature request

read more
Here you will find good setup tutorials!
Values from Synology
W

found the error, forgot to create two extra variables (SMART2 / Temp2)

read more
Discussion about Hardware.
XIAOMI Aqara Two-way Relay?

Hi folks,
just for the books.

Delivery and testing took a while, but the XIAOMI Aqara Two-way Relay works fine.
Simply discovered by the Phoscon App and now steered by my ConBee II.

As both built in relays can be switch independently, for sure for shutter steering usage, a respective rule has to be set up, to prevent that both are switched on at the same time.

As it is not really small (50x46x24mm) I fear that it will not fit into a normal wall switch hole.

read more

All about code

Plugin for Meross Devices

In a coproduction with @Wolfpack, the Meross plugin is developed, tested and ready for usage. It supports the SmartPlug (mss210) and the Garagedoor Opener (msg100). If there’s interest more devices can be added. Version 0.1.0 is available via the plugin page in Pimatic. The minimum node requirement is v8.

More info

read more
All about rules and script develpopment
Customize - ioBroker.pimatic

Sooo okay … i cant figure out how i get Updates for the Varaibles (Change in Pimatic -> Iobroker) … so i give up this point…
If some one find a solution tell me :)

Here is my final Version of my Mod, i changed now the placement of the variables back to the Iobroker “Devices” because its loot easy and i get rid of ~ 80 Warn-Entrys in the Iobroker-log. The Variables are marked with the Role “pimatic-variable”, so you can find them easy or filter for them. The push from Iobroker to Pimatic of the variables works fine. if you need also the Updates of the variables, create a “variablesdevices” in pimatic with the varaibles this the devices will be synct properly but the variables are readonly in the device.

0_1583444221608_bb7f9ed0-a0b3-4056-a337-b05289901972-image.png

Installation:

if you had only ready used the Adapter: stop the instance and delete the folder “devices” unter “Pimatic.0” replace the “main.js” under “opt/iobroker/node_modules/iobroker.pimatic” and start the Instance

Code for main.js:

/** * * pimatic adapter Copyright 2017, bluefox <dogafox@gmail.com> * */ /* jshint -W097 */ /* jshint strict:false */ /* jslint node: true */ 'use strict'; // you have to require the utils module and call adapter function var utils = require('@iobroker/adapter-core'); // Get common adapter utils var request = require('request'); var adapter = utils.Adapter('pimatic'); var io = require('socket.io-client'); var client; var objects = {}; var states = []; var connected = false; var url; var getUrl; var credentials; // is called when adapter shuts down - callback has to be called under any circumstances! adapter.on('unload', function (callback) { try { if (adapter.setState) adapter.setState('info.connection', false, true); if (client) client.disconnect(); client = null; adapter.log.info('cleaned everything up...'); callback(); } catch (e) { callback(); } }); // is called if a subscribed state changes adapter.on('stateChange', function (id, state) { if (state && !state.ack) { if (objects[id]) { if (objects[id].common.write && objects[id].native.control && objects[id].native.control.action) { states[id] = state.val; if (!connected) { adapter.log.warn('Cannot control: no connection to pimatic "' + adapter.config.host + '"'); } else { /*client.emit('call', { id: id, action: objects[id].native.control.action, params: { deviceId: objects[id].native.control.deviceId, name: objects[id].native.name, type: objects[id].common.type, valueOrExpression: state.val } });*/ // convert values if (objects[id].common.type === 'boolean') { state.val = (state.val === true || state.val === 'true' || state.val === '1' || state.val === 1 || state.val === 'on' || state.val === 'ON'); } else if (objects[id].common.type === 'number') { if (typeof state.val !== 'number') { if (state.val === true || state.val === 'true' || state.val === 'on' || state.val === 'ON') { state.val = 1; } else if (state.val === false || state.val === 'false' || state.val === 'off' || state.val === 'OFF') { state.val = 0; } else { state.val = parseFloat((state.val || '0').toString().replace(',', '.')); } } } // Update Variables mod by themilcho if (objects[id].native.control.action == 'updateVariable') { client.emit('call', { // id: id, id: objects[id].native.control.deviceId, action: 'updateVariable', params: { name: objects[id].native.control.deviceId, type: 'value', valueOrExpression: state.val } }); adapter.setForeignState(id, {val: state.val, ack: true}); } else { var link = getUrl + 'api/device/' + objects[id].native.control.deviceId + '/' + objects[id].native.control.action + '?' + objects[id].native.name + '=' + state.val; adapter.log.debug('http://' + link); request('http://' + credentials + link, function (err, res, body) { if (err || res.statusCode !== 200) { adapter.log.warn('Cannot write "' + id + '": ' + (body || err || res.statusCode)); adapter.setForeignState(id, {val: state.val, ack: true, q: 0x40}); } else { try { var data = JSON.parse(body); if (data.success) { adapter.log.debug(body); // the value will be updated in deviceAttributeChanged } else { adapter.log.warn('Cannot write "' + id + '": ' + body); adapter.setForeignState(id, {val: state.val, ack: true, q: 0x40}); } } catch (e) { adapter.log.warn('Cannot write "' + id + '": ' + body); adapter.setForeignState(id, {val: state.val, ack: true, q: 0x40}); } } }); } } } else { adapter.log.warn('State "' + id + '" is read only'); } } else { adapter.log.warn('Unknown state "' + id + '"'); } } }); // Some message was sent to adapter instance over message box. Used by email, pushover, text2speech, ... adapter.on('message', function (obj) { if (typeof obj === 'object' && obj.message) { if (obj.command === 'send') { // e.g. send email or pushover or whatever console.log('send command'); // Send response in callback if required if (obj.callback) adapter.sendTo(obj.from, obj.command, 'Message received', obj.callback); } } }); // is called when databases are connected and adapter received configuration. // start here! adapter.on('ready', function () { main(); }); function syncObjects(objs, callback) { if (!objs || !objs.length) { callback && callback(); return; } var obj = objs.shift(); adapter.getForeignObject(obj._id, function (err, oObj) { if (!oObj) { objects[obj._id] = obj; adapter.setForeignObject(obj._id, obj, function () { setTimeout(syncObjects, 0, objs, callback); }); } else { var changed = false; for (var a in obj.common) { if (obj.common.hasOwnProperty(a) && oObj.common[a] !== obj.common[a]) { changed = true; oObj.common[a] = obj.common[a]; } } if (JSON.stringify(obj.native) !== JSON.stringify(oObj.native)) { changed = true; oObj.native = obj.native; } objects[obj._id] = oObj; if (changed) { adapter.setForeignObject(oObj._id, oObj, function () { setTimeout(syncObjects, 0, objs, callback); }); } else { setTimeout(syncObjects, 0, objs, callback); } } }); } function syncStates(_states, callback) { if (!_states || !_states.length) { callback && callback(); return; } var state = _states.shift(); adapter.getForeignState(state._id, function (err, oState) { if (!oState) { adapter.setForeignState(state._id, state.val, function () { setTimeout(syncStates, 0, _states, callback); }); } else { var changed = false; for (var a in state.val) { if (state.val.hasOwnProperty(a) && (typeof state.val[a] !== 'object' && state.val[a] !== oState[a]) || (typeof state.val[a] === 'object' && JSON.stringify(state.val[a]) !== JSON.stringify(oState[a]))) { changed = true; oState[a] = state.val[a]; } } if (changed) { adapter.setForeignState(oState._id, oState, function () { setTimeout(syncStates, 0, _states, callback); }); } else { setTimeout(syncStates, 0, _states, callback); } } }); } function syncDevices(devices, callback) { var objs = []; var _states = []; for (var d = 0; d < devices.length; d++) { var localObjects = []; var device = devices[d]; // adapter.log.debug('Handle Device: ' + JSON.stringify(device)); adapter.log.debug('Handle Device: ' + device.id); var obj = { _id: adapter.namespace + '.devices.' + device.id, common: { name: device.name }, type: 'channel' }; objs.push(obj); var attributes = device.attributes; if ((!attributes || !attributes.length) && device.config) attributes = device.config.attributes; if (attributes && attributes.length) { for (var a = 0; a < attributes.length; a++) { var attr = attributes[a]; adapter.log.debug('Handle Attribute: ' + JSON.stringify(attr)); var id = adapter.namespace + '.devices.' + device.id + '.' + attr.name.replace(/\s/g, '_'); obj = { _id: id, common: { name: device.name + ' - ' + (attr.acronym || attr.name), desc: attr.description, type: attr.type, read: true, write: false, unit: attr.unit === 'c' ? '°C' : (attr.unit === 'f' ? '°F' : attr.unit) //role: acronym2role(attr.acronym) }, native: { }, type: 'state' }; _states.push({ _id: id, val: { ack: true, val: attr.value, ts: attr.lastUpdate } }); states[id] = attr.value; delete attr.value; delete attr.lastUpdate; delete attr.history; obj.native = attr; if (obj.common.type === 'boolean') { if (device.template === 'presence') obj.common.role = 'state';//'indicator.presence'; if (attr.labels && attr.labels[0] !== 'true') { obj.common.states = {false: attr.labels[1], true: attr.labels[0]}; } } else if (obj.common.type === 'number') { if (obj.common.unit === '°C' || obj.common.unit === '°F') { obj.common.role = 'value.temperature'; } else if (obj.common.unit === '%') { obj.common.min = 0; obj.common.max = 100; // Detect if temperature exists var found = false; for (var k = 0; k < localObjects.length; k++) { if (localObjects[k].common.unit === '°C' || localObjects[k].common.unit === '°F') { found = true; break; } } if (found) { obj.common.role = 'value.humidity'; } } if (attr.name === 'latitude') { obj.common.role = 'value.gps.latitude'; } else if (attr.name === 'longitude') { obj.common.role = 'value.gps.longitude'; } if (attr.name === 'gps') { obj.common.role = 'value.gps'; } } else { if (attr.name === 'battery') { obj.common.role = 'indicator.battery'; obj.native.mapping = {'ok': false, 'low': true}; obj.common.type = 'boolean'; obj.common.states = {false: 'ok', true: 'low'}; attr.value = (attr.value !== 'ok'); } } if (attr.enum && !obj.common.states) { obj.common.states = {}; for (var e = 0; e < attr.enum.length; e++) { if (attr.enum[e] === 'manu') { obj.common.states.manu = 'manual'; } else if (attr.enum[e] === 'auto') { obj.common.states.auto = 'automatic'; } else{ obj.common.states[attr.enum[e]] = attr.enum[e]; } } } objs.push(obj); localObjects.push(obj); } } var actions = device.actions; if ((!actions || !actions.length) && device.config) actions = device.config.actions; if (actions && actions.length) { for (var c = 0; c < actions.length; c++) { var action = actions[c]; for (var p in action.params) { if (!action.params.hasOwnProperty(p)) continue; // try to find state for that var _found = false; for (var u = 0; u < localObjects.length; u++) { if (localObjects[u].native.name === p) { _found = true; obj = localObjects[u]; obj.native.control = { action: action.name, deviceId: device.id }; obj.common.write = true; if (obj.common.role === 'value.temperature') obj.common.role = 'level.temperature'; } } if (!_found) { obj = { _id: adapter.namespace + '.devices.' + device.id + '.' + action.name.replace(/\s/g, '_') + '.' + p.replace(/\s/g, '_'), common: { desc: action.params[p].description || action.description, name: device.name + ' - ' + action.name + '.' + p, read: false, write: true, type: action.params[p].type }, native: { name: p, control: { action: action.name, deviceId: device.id } }, type: 'state' }; objs.push(obj); } } } } } var ids = []; for (var j = 0; j < objs.length; j++) { ids.push(objs[j]._id); objects[objs[j]._id] = objs[j]; } syncObjects(objs, function () { syncStates(_states, function () { callback && callback(ids); }); }); } //Update variables mod by tehmilcho function syncVariables(variables, callback) { var objs = []; var _states = []; for (var v = 0; v < variables.length; v++) { var localObjects = []; var variable = variables[v]; if (variable.readonly == false) { adapter.log.debug('Handle Variables: ' + JSON.stringify(variable)); var obj = { _id: adapter.namespace + '.devices.' + variable.name, common: { name: variable.name, read: true, write: true, role: 'pimatic-variable' }, native: { name: variable.name, control: { action: 'updateVariable', deviceId: variable.name } }, type: 'state' }; _states.push({ _id: adapter.namespace + '.devices.' + variable.name, val: { ack: true, val: variable.value, } }); objs.push(obj); localObjects.push(obj); } } var ids = []; for (var vj = 0; vj < objs.length; vj++) { ids.push(objs[vj]._id); objects[objs[vj]._id] = objs[vj]; } syncObjects(objs, function () { syncStates(_states, function () { callback && callback(ids); }); }); } function syncGroups(groups, ids, callback) { var enums = []; var obj = { _id: 'enum.pimatic', common: { members: [], name: 'Pimatic groups' }, native: {}, type: 'enum' }; enums.push(obj); for (var g = 0; g < groups.length; g++) { obj = { _id: 'enum.pimatic.' + groups[g].id, type: 'enum', common: { name: groups[g].name, members: [] }, native: {} }; for (var m = 0; m < groups[g].devices.length; m++) { var id = adapter.namespace + '.devices.' + groups[g].devices[m].replace(/\s/g, '_'); if (ids.indexOf(id) === -1) { // try to find var found = false; var _id = id.toLowerCase(); for (var i = 0; i < ids.length; i++) { if (ids[i].toLowerCase() === _id) { id = ids[i]; found = true; break; } } if (found) { obj.common.members.push(id); } else { adapter.log.warn('Device "' + groups[g].devices[m] + '" was found in the group "' + groups[g].name + '", but not found in devices'); } } else { obj.common.members.push(id); } } enums.push(obj); } syncObjects(enums, callback); } function updateConnected(isConnected) { if (connected !== isConnected) { connected = isConnected; adapter.setState('info.connection', connected, true); adapter.log.info(isConnected ? 'connected' : 'disconnected'); } } function connect() { url = url || 'http://' + adapter.config.host + (adapter.config.port ? ':' + adapter.config.port : '') + '/?username=' + encodeURIComponent(adapter.config.username) + '&password='; credentials = credentials || encodeURIComponent(adapter.config.username) + ':' + encodeURIComponent(adapter.config.password); getUrl = getUrl || '@' + adapter.config.host + (adapter.config.port ? ':' + adapter.config.port : '') + '/'; adapter.log.debug('Connect: ' + url + 'xxx'); client = io.connect(url + encodeURIComponent(adapter.config.password), { reconnection: true, reconnectionDelay: 1000, reconnectionDelayMax: 3000, timeout: 20000, forceNew: true }); client.on('connect', function() { updateConnected(true); }); client.on('event', function (data) { adapter.log.debug(data); }); client.on('disconnect', function (data) { updateConnected(false); }); client.on('devices', function (devices) { updateConnected(true); syncDevices(devices); }); client.on('rules', function (rules) { //adapter.log.debug('Rules ' + JSON.stringify(rules)); }); client.on('variables', function (variables) { syncVariables(variables); var _states = []; for (var s = 0; s < variables.length; s++) { if (variables[s].value !== undefined && variables[s].value !== null) { var state = { _id: adapter.namespace + '.devices.' + variables[s].name.replace(/\s/g, '_'), val: { val: variables[s].value, ack: true } }; if (objects[state._id]) { if (objects[state._id].native && objects[state._id].native.mapping) { if (objects[state._id].native.mapping[variables[s].value] !== undefined) { state.val.val = objects[state._id].native.mapping[variables[s].value]; } } _states.push(state); } else { adapter.log.warn('Unknown state: ' + state._id); } } } syncStates(_states); }); client.on('pages', function (pages) { //adapter.log.debug('pages ' + JSON.stringify(pages)); }); client.on('groups', function (groups) { updateConnected(true); var ids = []; for (var id in objects) { ids.push(id); } syncGroups(groups, ids); }); client.on('deviceAttributeChanged', function (attrEvent) { if (!attrEvent.deviceId || !attrEvent.attributeName) { adapter.log.warn('Received invalid event: ' + JSON.stringify(attrEvent)); return; } var name = attrEvent.deviceId.replace(/\s/g, '_') + '.' + attrEvent.attributeName.replace(/\s/g, '_'); adapter.log.debug('update for "' + name + '": ' + JSON.stringify(attrEvent)); //{deviceId: device.id, attributeName, time: time.getTime(), value} var id = adapter.namespace + '.devices.' + name; if (objects[id]) { adapter.setForeignState(id, {val: attrEvent.value, ts: attrEvent.time, ack: true}); } else { adapter.log.warn('Received update for unknown state: '+ id + ' ' + JSON.stringify(attrEvent)); } }); client.on('callResult', function (msg) { if (objects[msg.id]) { adapter.setForeignState(msg.id, states[msg.id].val, true); } }); } function main() { adapter.setState('info.connection', false, true); connect(); // in this pimatic all states changes inside the adapters namespace are subscribed adapter.subscribeStates('*'); }

read more
Please report bugs on github!

Looks like your connection to pimatic forum was lost, please wait while we try to reconnect.