Hallo!
ich habe auch beschlossen mich Mal mit dem Thema zu beschaeftigen.
Die ersten Nodes laufen und ich habe angefangen mich um die IPS Integration zu kuemmern.
Zuerst hatte ich geguckt, ob es Sinn macht eine vorhandenen Controller Software als IPS Gateway zu patchen. Die ideale Basis habe ich aber leider nicht gefunden.
Danach habe ich MQTT als Gateway zu IPS probiert. Da hier der Controller auch in IPS implemetiert werden muss, habe ich dann beschlossen direkt mit dem Gateway (in meinem Fall Ethernet) zu reden.
Momentan ist das Script noch ‚work in progress‘, aber einige Sachen gehen schon.
Es muss ein ‚Client Socket‘ und ein ‚RegisterVariable‘ angelegt werden. ‚RegisterVariable‘ triggert das Script unten, welches am besten in einer eigenen Kategorie liegt.
Pro Node wird automatisch eine Conf Variable angelegt und eine freie ID vergeben. Die Conf Variable haelt ein Array mit den IPS Var IDs der jeweiligen MySensor Child Variablen. Das hat den Vorteil, das alle automatisch angelegten Varibalen beliebig umbenannt und verschoben werden koennen.
Ansatzweise setzt das Script auch schon den richtigen Variablen Typ und Profil.
Leider ist mir noch nicht ganz klar, ob, bzw. wie MySensors definiert, welchen Variablen Typ ein Child nutzt und ob eine Variable Read, Write oder Read/Write ist.
Letztendlich moechte ich aber, das z.B. ein Relay Node auch automatisch aus dem Webfront geschaltet werden kann.
Wie gesagt, ugly work in progress…
<?
print ( $_IPS['VALUE']);
$mysensors_base_category = IPS_GetParent($_IPS['SELF']);
$mysensors_client_socket = 17889 /*[Client Socket MySensors]*/;
$topic_level = explode(";", $_IPS['VALUE']);
$node_id = $topic_level[0];
$child_id = $topic_level[1];
$message_type = $topic_level[2];
$ack = $topic_level[3];
$sub_type = $topic_level[4];
$payload = trim(@$topic_level[5], "
");; //sometimes no payload, ignore.
$ms_msg_type = array(
0 => 'presentation',
1 => 'set',
2 => 'req',
3 => 'internal',
4 => 'stream',
);
$ms_s_type = array(
0 => 'S_DOOR',
1 => 'S_MOTION',
2 => 'S_SMOKE',
//3 => 'S_LIGHT',
3 => 'S_BINARY',
4 => 'S_DIMMER',
5 => 'S_COVER',
6 => 'S_TEMP',
7 => 'S_HUM',
8 => 'S_BARO',
9 => 'S_WIND',
10 => 'S_RAIN',
11 => 'S_UV',
12 => 'S_WEIGHT',
13 => 'S_POWER',
14 => 'S_HEATER',
15 => 'S_DISTANCE',
16 => 'S_LIGHT_LEVEL',
17 => 'S_ARDUINO_NODE',
18 => 'S_ARDUINO_REPEATER_NODE',
19 => 'S_LOCK',
20 => 'S_IR',
21 => 'S_WATER',
22 => 'S_AIR_QUALITY',
23 => 'S_CUSTOM',
24 => 'S_DUST',
25 => 'S_SCENE_CONTROLLER',
26 => 'S_RGB_LIGHT',
27 => 'S_RGBW_LIGHT',
28 => 'S_COLOR_SENSOR',
29 => 'S_HVAC',
30 => 'S_MULTIMETER',
31 => 'S_SPRINKLER',
32 => 'S_WATER_LEAK',
33 => 'S_SOUND',
34 => 'S_VIBRATION',
35 => 'S_MOISTURE',
255 => 'S_PRESENTATION',
);
/*
0 Legt eine Variable vom Typ Boolean an
1 Legt eine Variable vom Typ Integer an
2 Legt eine Variable vom Typ Float an
3 Legt eine Variable vom Typ String an
*/
/*
~Mode.HM
~Milliampere.HM
~Temperature.HM
~Window.HM
~Electricity.HM
~Motion.HM
~Volt.230
~Raining
~ShutterPosition.255
~ShutterAssociation
~Battery.Reversed
~WindDirection.Text
~WindDirection
~WindSpeed.ms
~WindSpeed.kmh
~Motion
~Valve.F
~Battery.100
~ShutterPosition.100
~Intensity.100
~Temperature.Difference
~Motion.Reversed
~Humidity.F
~Presence.Reversed
~Valve
~Temperature
~Illumination.F
~Temperature.Room
~Temperature.Fahrenheit
~Intensity.32767
~MailMessages
~Occurrence.CO2
~AirPressure.F
~Alert
~WindDirection.F
~UVIndex
~Switch
~Intensity.1
~Battery
~Illumination
~Presence
~Lock.Reversed
~HTMLBox
~Alert.Reversed
~Brightness.HM
~ShutterMove
~Window.Reversed
~Volt
~Shutter
~Lock
~Ampere
~Ampere.16
~Watt.3680
~Humidity
~Watt.14490
~Hertz
~Hertz.50
~Intensity.255
~Electricity
~Water
~Gas
~Power
~Window
~Flow
~String
~UnixTimestamp
~TextBox
~Rainfall
~HexColor
~AirPressure
*/
//arrays to be finished...
$ms_v_type = array(
0 => array('v_type_name' => 'V_TEMP', 'ips_v_type' => 2, 'ips_v_profile' => '~Temperature'),
1 => array('v_type_name' => 'V_HUM', 'ips_v_type' => 2, 'ips_v_profile' => '~Humidity.F'),
2 => array('v_type_name' => 'V_STATUS', 'ips_v_type' => 0, 'ips_v_profile' => '~Switch'),
//2 => 'V_LIGHT',
3 => array('v_type_name' => 'V_PERCENTAGE','ips_v_type' => 2, 'ips_v_profile' => '~Intensity.100'),
//3 => 'V_DIMMER',
4 => array('v_type_name' => 'V_PRESSURE', 'ips_v_type' => 2, 'ips_v_profile' => '~AirPressure'),
5 => 'V_FORECAST',
6 => 'V_RAIN',
7 => 'V_RAINRATE',
8 => 'V_WIND',
9 => 'V_GUST',
10 => 'V_DIRECTION',
11 => 'V_UV',
12 => 'V_WEIGHT',
13 => 'V_DISTANCE',
14 => 'V_IMPEDANCE',
15 => 'V_ARMED',
16 => 'V_TRIPPED',
17 => 'V_WATT',
18 => 'V_KWH',
19 => 'V_SCENE_ON',
20 => 'V_SCENE_OFF',
21 => 'V_HVAC_FLOW_STATE',
22 => 'V_HVAC_SPEED',
23 => 'V_LIGHT_LEVEL',
24 => 'V_VAR1',
25 => 'V_VAR2',
26 => 'V_VAR3',
27 => 'V_VAR4',
28 => 'V_VAR5',
29 => 'V_UP',
30 => 'V_DOWN',
31 => 'V_STOP',
32 => 'V_IR_SEND',
33 => 'V_IR_RECEIVE',
34 => 'V_FLOW',
35 => 'V_VOLUME',
36 => 'V_LOCK_STATUS',
37 => 'V_LEVEL',
38 => array('v_type_name' => 'V_VOLTAGE', 'ips_v_type' => 1, 'ips_v_profile' => '~Volt'), //well, actually mV...
39 => 'V_CURRENT',
40 => 'V_RGB',
41 => 'V_RGBW',
42 => 'V_ID',
43 => 'V_UNIT_PREFIX',
44 => 'V_HVAC_SETPOINT_COOL',
45 => 'V_HVAC_SETPOINT_HEAT',
46 => 'V_HVAC_FLOW_MODE',
);
$ms_i_type = array(
0 => 'I_BATTERY_LEVEL',
1 => 'I_TIME',
2 => 'I_VERSION',
3 => 'I_ID_REQUEST',
4 => 'I_ID_RESPONSE',
5 => 'I_INCLUSION_MODE',
6 => 'I_CONFIG',
7 => 'I_FIND_PARENT',
8 => 'I_FIND_PARENT_RESPONSE',
9 => 'I_LOG_MESSAGE',
10 => 'I_CHILDREN',
11 => 'I_SKETCH_NAME',
12 => 'I_SKETCH_VERSION',
13 => 'I_REBOOT',
14 => 'I_GATEWAY_READY',
15 => 'I_REQUEST_SIGNING',
16 => 'I_GET_NONCE',
17 => 'I_GET_NONCE_RESPONSE',
);
//parse different message types
switch ($ms_msg_type[$message_type])
{
//($node_id, $child_sensor_id, $message_type, $ack, $sub_type, $payload)
case 'presentation':
print "Node:" .$node_id
." - Child:" .$child_id
." - Func:" .$ms_msg_type[$message_type]
." - ACK:" .$ack
." - Sub-Type:" .$ms_s_type[$sub_type]//['v_type_name']
." - Payload:" .$payload
."
";
$node_conf_var = create_node_conf($node_id);
$node_conf = unserialize(GetValueString($node_conf_var));
//a new node?
if (!@array_key_exists ('node_id_' .$node_id, $node_conf)) //ignore empty conf warning
{
echo "creating node instance
";
$instance_id = IPS_CreateInstance("{485D0419-BE97-4548-AA9C-C083EB82E61E}"); //dummy
IPS_SetParent($instance_id, $mysensors_base_category);
IPS_SetName($instance_id, "node ID" .$node_id);
$node_conf['node_id_' .$node_id] = $instance_id;
}
//a new child?
if (!@array_key_exists ('child_id_' .$child_id, $node_conf)) //ignore empty conf warning
{
echo "creating child variable
";
$child_var_id = IPS_CreateVariable(3); //since we don't know the var type yet, set it to string for the moment
IPS_SetParent($child_var_id, $node_conf['node_id_' .$node_id]);
IPS_SetName($child_var_id, "child ID" .$child_id .':' .$payload);
$node_conf['child_id_' .$child_id] = $child_var_id;
}
//should we acknolege? correct way to be checked..
if($ack === '1')
{
echo "send ack";
CSCK_SendText($mysensors_client_socket, $node_id .';' .$child_id .';' .$message_type .';1;' .$sub_type .';' .$payload .';' .chr(0x0a));
}
break;
case 'set':
print "Node:" .$node_id
." - Child:" .$child_id
." - Func:" .$ms_msg_type[$message_type]
." - ACK:" .$ack
." - Sub-Type:" .$ms_v_type[$sub_type]['v_type_name']
." - Payload:" .$payload
."
";
$node_conf_var = get_node_conf($node_id);
//skip unknown nodes.
if(!$node_conf_var)
{
print "unknown node id" .$node_id ."- skipping";
exit;
}
$node_conf = unserialize(GetValueString($node_conf_var));
//var type is not 100% known during presentation. check if it was already updated.
if(IPS_GetVariable($node_conf['child_id_' .$child_id])['VariableType'] != $ms_v_type[$sub_type]['ips_v_type'])
{
Print "updating var type
";
$old_var_name = IPS_GetName($node_conf['child_id_' .$child_id]);
IPS_DeleteVariable($node_conf['child_id_' .$child_id]);
$child_var_id = IPS_CreateVariable($ms_v_type[$sub_type]['ips_v_type']);
$node_conf['child_id_' .$child_id] = $child_var_id;
IPS_SetParent($child_var_id, $node_conf['node_id_' .$node_id]);
IPS_SetName($child_var_id, $old_var_name);
IPS_SetVariableCustomProfile($child_var_id, $ms_v_type[$sub_type]['ips_v_profile']);
}
echo "payload" .$payload ."#";
//cast the payload into the right type and write it to ips variable
switch ($ms_v_type[$sub_type]['ips_v_type'])
{
case 0: SetValue($node_conf['child_id_' .$child_id], (bool)$payload); break; //it's bool
case 1: SetValue($node_conf['child_id_' .$child_id], (integer)$payload); break; //it's int
case 2: SetValue($node_conf['child_id_' .$child_id], (float)$payload); break; //it's float
case 3: SetValue($node_conf['child_id_' .$child_id], (string)$payload); break; //it's string
}
break;
case 'req':
print "Node:" .$node_id
." - Child:" .$child_id
." - Func:" .$ms_msg_type[$message_type]
." - ACK:" .$ack
." - Sub-Type:" .$ms_v_type[$sub_type]
." - Payload:" .$payload;
break;
case 'internal':
print "Node:" .$node_id
." - Child:" .$child_id
." - Func:" .$ms_msg_type[$message_type]
." - ACK:" .$ack
." - Sub-Type:" .$ms_i_type[$sub_type]
." - Payload:" .$payload;
switch ($ms_i_type[$sub_type])
{
case 'I_ID_REQUEST':
//find a node addess free to assign
$id=1;
while ($id <= 254)
{
$free_node_id = @IPS_GetVariableIDByName('node_id_' .$id, $mysensors_base_category);
if(!$free_node_id) break;
$id++;
}
if ($id > 254)
{
print "no more free node IDs - skipping.";
exit;
}
echo 'sending new ID ' .$id;
CSCK_SendText($mysensors_client_socket, '255;255;3;0;4;' .$id .';' .chr(0x0a));
break;
case 'I_CONFIG':
echo 'send I_CONFIG';
//correct way? to be checked...
CSCK_SendText($mysensors_client_socket, $node_id .';' .$child_id .';3;0;6;M;' .chr(0x0a));
break;
}
break;
case 'stream':
echo 'stream is not supported, yet';
break;
}
if (isset($node_conf_var))
{
SetValueString($node_conf_var , serialize($node_conf));
print_r ($node_conf);
}
/*----------------------------------------------------------------------------*/
function create_node_conf($node_id)
{
$parent_category = IPS_GetParent($_IPS['SELF']);
$var_node_id = @IPS_GetVariableIDByName("node_id_" .$node_id, $parent_category);
if($var_node_id === false)
{
echo "creating missing node conf variable for ID:" .$node_id ."
";
$var_node_id = IPS_CreateVariable(3);
IPS_SetName($var_node_id , "node_id_" .$node_id);
IPS_SetParent($var_node_id, $parent_category);
}
return $var_node_id;
}
function get_node_conf($node_id)
{
$parent_category = IPS_GetParent($_IPS['SELF']);
$var_node_id = @IPS_GetVariableIDByName("node_id_" .$node_id, $parent_category);
return $var_node_id;
}
?>
So, ich werde Mal weiter machen. Comments welcome!
Gruss, Michael