- debug\n- webserver fonctionnel
This commit is contained in:
parent
a29aa9b653
commit
9d10e51a24
@ -9,7 +9,7 @@ class hook
|
|||||||
// list of devices we are listening to
|
// list of devices we are listening to
|
||||||
function __construct()
|
function __construct()
|
||||||
{
|
{
|
||||||
logger(DEBUG, _("Initializing hook: ") . $this->hookName);
|
logger(INFO, _("Initializing hook: ") . $this->hookName);
|
||||||
$this->installHooks();
|
$this->installHooks();
|
||||||
if (method_exists($this, "init"))
|
if (method_exists($this, "init"))
|
||||||
{
|
{
|
||||||
@ -50,13 +50,13 @@ class hook
|
|||||||
if ($result === true)
|
if ($result === true)
|
||||||
{
|
{
|
||||||
$this->initialized = true;
|
$this->initialized = true;
|
||||||
logger(DEBUG, $this->hookName . _(" initialized"), __FILE__ . ":" . __LINE__);
|
logger(INFO, $this->hookName . _(" initialized"), __FILE__ . ":" . __LINE__);
|
||||||
//var_dump($this);
|
//var_dump($this);
|
||||||
}
|
}
|
||||||
}else
|
}else
|
||||||
{
|
{
|
||||||
$this->initialized = true;
|
$this->initialized = true;
|
||||||
logger(DEBUG, $this->hookName . _("hook is disabled"), __FILE__ . ":" . __LINE__);
|
logger(INFO, $this->hookName . _("hook is disabled"), __FILE__ . ":" . __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
|
18
config/aliases.php
Normal file
18
config/aliases.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
function aliases($fn, $property)
|
||||||
|
{
|
||||||
|
global $aliases;
|
||||||
|
logger(DEBUG, "Function aliases " . $fn . "/" . $property, __FILE__ . ":" . __LINE__);
|
||||||
|
if (array_key_exists($fn . "/" . $property, $aliases))
|
||||||
|
{
|
||||||
|
logger(DEBUG, "exists " . $fn . "/" . $property, __FILE__ . ":" . __LINE__);
|
||||||
|
return "/" . $aliases[$fn . "/" . $property];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$aliases = array(
|
||||||
|
"rdc/wc-sdb/eclairage/state_l1" => "sdb",
|
||||||
|
"rdc/wc-sdb/eclairage/state_l2" => "wc"
|
||||||
|
)
|
||||||
|
|
||||||
|
?>
|
@ -1,10 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
$dashboards[] = array(
|
$dashboards[0] = array(
|
||||||
RDC_SALON_ECLAIRAGE_PANNEAU => "state",
|
array(RDC_SALON_ECLAIRAGE_PANNEAU, "state"),
|
||||||
RDC_SDB_WC_ECLAIRAGE => "state_l1",
|
array(RDC_SDB_WC_ECLAIRAGE, "state_l1"),
|
||||||
RDC_SDB_WC_ECLAIRAGE => "state_l2",
|
array(RDC_SDB_WC_ECLAIRAGE, "state_l2"),
|
||||||
RDC_CHAMBRE_AMBIANCE => "state",
|
array(RDC_CHAMBRE_AMBIANCE, "state"),
|
||||||
RDC_CHAMBRE_ECLAIRAGE => "state_l1"
|
array(RDC_CHAMBRE_ECLAIRAGE, "state_l1")
|
||||||
);
|
);
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
@ -18,7 +18,6 @@ $properties2log = array(
|
|||||||
"position" => null,
|
"position" => null,
|
||||||
"pressure" => 10,
|
"pressure" => 10,
|
||||||
"occupancy" => null,
|
"occupancy" => null,
|
||||||
"tamper" => null,
|
|
||||||
"illuminance_lux" => function($value) {($value < 500?50:$value*10/100); return $value;},
|
"illuminance_lux" => function($value) {($value < 500?50:$value*10/100); return $value;},
|
||||||
// "illuminance" => 8,
|
// "illuminance" => 8,
|
||||||
"requested_brightness_level" => function($value) {($value < 500?50:$value*10/100);return $value;},
|
"requested_brightness_level" => function($value) {($value < 500?50:$value*10/100);return $value;},
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
//Constants
|
//Constants
|
||||||
define("EOL", "\n");
|
define("EOL", "\n");
|
||||||
define("EOLR", "\n\r");
|
define("EOLR", "\n\r");
|
||||||
|
define("EOLH", "<br>\n");
|
||||||
define("Z2M", "zigbee2mqtt");
|
define("Z2M", "zigbee2mqtt");
|
||||||
define("ON", true);
|
define("ON", true);
|
||||||
define("OFF", false);
|
define("OFF", false);
|
||||||
|
@ -21,7 +21,7 @@ function loadDB(& $db, $filepath)
|
|||||||
|
|
||||||
function mkDevicesDB($topic, $json, $group=false)
|
function mkDevicesDB($topic, $json, $group=false)
|
||||||
{
|
{
|
||||||
global $devices, $listProperties, $listPropertiesKeys, $indexDevices, $dbInit, $logFh, $hooks;
|
global $devices, $listProperties, $listPropertiesKeys, $indexDevices, $dbInit, $logFh, $hooks, $indexFriendlyNames;
|
||||||
if (!isset($devices[$topic]))
|
if (!isset($devices[$topic]))
|
||||||
{
|
{
|
||||||
$devices[$topic]= array();
|
$devices[$topic]= array();
|
||||||
@ -63,7 +63,7 @@ function mkDevicesDB($topic, $json, $group=false)
|
|||||||
fwrite($logFh, "################################START##################################################");
|
fwrite($logFh, "################################START##################################################");
|
||||||
fwrite($logFh, var_export($devices, true));
|
fwrite($logFh, var_export($devices, true));
|
||||||
fwrite($logFh, "################################END##################################################");
|
fwrite($logFh, "################################END##################################################");
|
||||||
logger(DEBUG, _("Devices DB made"), __FILE__ . ":" . __LINE__);
|
logger(INFO, _("Devices DB made"), __FILE__ . ":" . __LINE__);
|
||||||
//print_r($devices);
|
//print_r($devices);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,16 +99,17 @@ function searchPropertyKey($fn, &$device, $inputObject, $listPropertiesKeys)
|
|||||||
{
|
{
|
||||||
logger(DEBUG, _("propertyKey exists filling properties"), __FILE__ . ":" . __LINE__ );
|
logger(DEBUG, _("propertyKey exists filling properties"), __FILE__ . ":" . __LINE__ );
|
||||||
$string = $inputObject->property;
|
$string = $inputObject->property;
|
||||||
|
if (!array_key_exists($string, $device->properties))
|
||||||
|
{
|
||||||
$device->properties[$string]["value"] = null;
|
$device->properties[$string]["value"] = null;
|
||||||
|
}
|
||||||
$device->properties[$string]["functions"] = array();
|
$device->properties[$string]["functions"] = array();
|
||||||
|
|
||||||
foreach($inputObject as $key2 => $value2)
|
foreach($inputObject as $key2 => $value2)
|
||||||
{
|
{
|
||||||
|
|
||||||
if ($key2 != "property")
|
if ($key2 != "property")
|
||||||
{
|
{
|
||||||
$device->properties[$string][$key2] = $value2;
|
$device->properties[$string][$key2] = $value2;
|
||||||
logger(DEBUG, sprintf(_("property %s value %s"), $key2, print_r($device->properties[$string][$key2])), __FILE__ . ":" . __LINE__ );
|
//logger(DEBUG, sprintf(_("property %s value %s"), $key2, print_r($device->properties[$string][$key2])), __FILE__ . ":" . __LINE__ );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else
|
}else
|
||||||
@ -154,8 +155,6 @@ function changeDevice($topic, $fn, &$device, $payloadArray)
|
|||||||
//print_r($payloadArray);
|
//print_r($payloadArray);
|
||||||
if (!empty($payloadArray))
|
if (!empty($payloadArray))
|
||||||
{
|
{
|
||||||
//echo "==================== New ChangeDevice =====================" .EOL;
|
|
||||||
|
|
||||||
iterateDevice($topic, $fn, $device, $device->properties, $payloadArray);
|
iterateDevice($topic, $fn, $device, $device->properties, $payloadArray);
|
||||||
}else
|
}else
|
||||||
{
|
{
|
||||||
@ -194,11 +193,13 @@ function iterateDevice($topic, $fn, $parentDevice, &$properties, $payloadArray,
|
|||||||
{
|
{
|
||||||
$properties[$key] = array("value" => $value);
|
$properties[$key] = array("value" => $value);
|
||||||
$properties[$key]["functions"] = array();
|
$properties[$key]["functions"] = array();
|
||||||
}
|
}elseif ($properties[$key]["value"] !== $value)
|
||||||
|
{
|
||||||
changeValue($properties[$key], $value, $parentDevice, $propertyTree, $key);
|
changeValue($properties[$key], $value, $parentDevice, $propertyTree, $key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getDevicesValues($topic)
|
function getDevicesValues($topic)
|
||||||
{
|
{
|
||||||
@ -216,9 +217,15 @@ function getDevicesValues($topic)
|
|||||||
if (!empty($device->properties))
|
if (!empty($device->properties))
|
||||||
{
|
{
|
||||||
foreach($device->properties as $property => $value)
|
foreach($device->properties as $property => $value)
|
||||||
|
{
|
||||||
|
if (array_key_exists("access", $value))
|
||||||
|
{
|
||||||
|
if ($value["access"] & 5)
|
||||||
{
|
{
|
||||||
$device->payload[$property] = "";
|
$device->payload[$property] = "";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
//logger(DEBUG, print_r($device->payload, true), __FILE__ . ":" . __LINE__ );
|
//logger(DEBUG, print_r($device->payload, true), __FILE__ . ":" . __LINE__ );
|
||||||
$device->get();
|
$device->get();
|
||||||
}else
|
}else
|
||||||
@ -230,47 +237,6 @@ function getDevicesValues($topic)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*function getDeviceByFriendlyname(&$device, $topic, $fn, $payloadArray, $create = false)
|
|
||||||
{
|
|
||||||
global $devices, $indexDevices, $indexFriendlyNames;
|
|
||||||
$n = explode("/", $fn);
|
|
||||||
$device = &$devices[$topic];
|
|
||||||
foreach($n as $value)
|
|
||||||
{
|
|
||||||
//print_r($device[$value]);
|
|
||||||
if (array_key_exists($value, $device))
|
|
||||||
{
|
|
||||||
$device = &$device[$value];
|
|
||||||
}elseif($create === true)
|
|
||||||
{
|
|
||||||
$device[$value] = array();
|
|
||||||
$device = &$device[$value];
|
|
||||||
}else
|
|
||||||
{
|
|
||||||
logger(ERROR, sprintf(_(" device with friendlyname %s not found"), $fn), __FILE__ . ":" . __LINE__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (! array_key_exists("device", $device))
|
|
||||||
{
|
|
||||||
if ($create === true)
|
|
||||||
{
|
|
||||||
logger(WARNING, _("init of ") . $fn, __FILE__ . ":" . __LINE__);
|
|
||||||
$device["device"] = new device;
|
|
||||||
$device["device"]->type = $payloadArray->type;
|
|
||||||
$device["device"]->ieeeAddress = $payloadArray->ieeeAddress;
|
|
||||||
$device["device"]->friendlyname = $fn;
|
|
||||||
$indexDevices[$device["device"]->ieeeAddress] = & $device["device"];
|
|
||||||
$indexFriendlyNames[$topic][$fn] = & $device["device"];
|
|
||||||
}
|
|
||||||
}else
|
|
||||||
{
|
|
||||||
logger(INFO, sprintf(_(" device with friendlyname %s exists"), $fn), __FILE__ . ":" . __LINE__);
|
|
||||||
}
|
|
||||||
//var_dump($device);
|
|
||||||
return true;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
function changeValue(&$property, $value, &$parentDevice, $propertyTree, $key)
|
function changeValue(&$property, $value, &$parentDevice, $propertyTree, $key)
|
||||||
{
|
{
|
||||||
global $mohaDB;
|
global $mohaDB;
|
||||||
|
@ -161,12 +161,13 @@ function setDelay(&$deviceObject, $delay, $unit, $property, $value, $replace=fal
|
|||||||
|
|
||||||
function removeEvent($deviceObject, $property , $value)
|
function removeEvent($deviceObject, $property , $value)
|
||||||
{
|
{
|
||||||
if (($eventKey = searchEvent($deviceObject, $property , $value)) === true)
|
$eventKey = searchEvent($deviceObject, $property , $value);
|
||||||
|
if ($eventKey !== false)
|
||||||
{
|
{
|
||||||
deleteEvent($eventKey);
|
deleteEvent($eventKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchEvent($deviceObject, $property , $value)
|
function searchEvent($deviceObject, $property , $value)
|
||||||
{
|
{
|
||||||
global $events;
|
global $events;
|
||||||
|
@ -45,14 +45,7 @@ class availability
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//echo sprintf(_("notification received from MQTT -> device %s is %s"), $device->friendlyName , $value). EOL;
|
|
||||||
//echo $property . "=> " . $value . EOL;
|
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
public function getHook()
|
|
||||||
{
|
|
||||||
return array($this,"callback");
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$hooks["availability"] = new availability();
|
$hooks["availability"] = new availability();
|
||||||
|
@ -26,21 +26,27 @@ class rdc_chambre_eclairage extends hook
|
|||||||
$targetAmbiance = $indexDevices[RDC_CHAMBRE_AMBIANCE];
|
$targetAmbiance = $indexDevices[RDC_CHAMBRE_AMBIANCE];
|
||||||
$targetEclairage = $indexDevices[RDC_CHAMBRE_ECLAIRAGE];
|
$targetEclairage = $indexDevices[RDC_CHAMBRE_ECLAIRAGE];
|
||||||
|
|
||||||
if ($property == "occupancy" and $value == "ON")
|
if ($property == "occupancy" and $value == ON)
|
||||||
{
|
{
|
||||||
$this->send($targetAmbiance, "ON", "OFF", AUTO);
|
$this->send($targetAmbiance, "state", "ON", "OFF", AUTO);
|
||||||
}elseif ($property == "contact" and $value = true and getValue(RDC_CHAMBRE_ECLAIRAGE, "state_l1") == "OFF")
|
}elseif ($property == "contact")
|
||||||
{
|
{
|
||||||
$this->send($targetEclairage, "ON", "OFF", AUTO);
|
if ($value == false and getValue(RDC_CHAMBRE_ECLAIRAGE, "state_l1") == "OFF")
|
||||||
|
{
|
||||||
|
$this->send($targetEclairage, "state_l1", "ON", "OFF", AUTO);
|
||||||
|
}elseif ($value == true and getValue(RDC_CHAMBRE_ECLAIRAGE, "state_l1") == "ON")
|
||||||
|
{
|
||||||
|
$this->send($targetEclairage, "state_l1", "OFF", null, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
logger (INFO, sprintf(_("%s: notification received from MQTT from %s => parameter: %s value: %s"), $this->hookName, $device->friendlyName, $property, bool2string($value)), __FILE__ . ":" . __LINE__);
|
logger (INFO, sprintf(_("%s: notification received from MQTT from %s => parameter: %s value: %s"), $this->hookName, $device->friendlyName, $property, bool2string($value)), __FILE__ . ":" . __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function send($deviceObject, $state, $delayState = false, $method = MANUAL)
|
private function send($deviceObject, $property, $state, $delayState = false, $method = MANUAL)
|
||||||
{
|
{
|
||||||
global $devices, $indexDevices;
|
global $devices, $indexDevices;
|
||||||
$msg = array("state_l1" => $state);
|
$msg = array($property => $state);
|
||||||
if ($deviceObject->properties["state_l1"]["value"] != $state)
|
if ($deviceObject->properties[$property]["value"] != $state)
|
||||||
{
|
{
|
||||||
logger(INFO, sprintf(_("publishing message: %s to %s"), json_encode($msg), $deviceObject->friendlyName), __FILE__ . ":" . __LINE__);
|
logger(INFO, sprintf(_("publishing message: %s to %s"), json_encode($msg), $deviceObject->friendlyName), __FILE__ . ":" . __LINE__);
|
||||||
$deviceObject->payload = $msg;
|
$deviceObject->payload = $msg;
|
||||||
|
@ -22,7 +22,7 @@ class rdc_wc_eclairage extends hook
|
|||||||
{
|
{
|
||||||
setDelay($device, $this->delayManual, $this->timeUnit, "state_l2", "OFF", true);
|
setDelay($device, $this->delayManual, $this->timeUnit, "state_l2", "OFF", true);
|
||||||
$device->method = MANUAL;
|
$device->method = MANUAL;
|
||||||
}elseif ($value = "OFF")
|
}elseif ($value == "OFF")
|
||||||
{
|
{
|
||||||
deleteEvent(searchEvent($device, "state_l2", "OFF"));
|
deleteEvent(searchEvent($device, "state_l2", "OFF"));
|
||||||
}
|
}
|
||||||
|
6
moha.php
6
moha.php
@ -44,13 +44,15 @@ if ($testMode)
|
|||||||
$dataPath = "./";
|
$dataPath = "./";
|
||||||
$logFile = "./moha.log"; // Path of log file
|
$logFile = "./moha.log"; // Path of log file
|
||||||
$configDir = "./config"; // default config dir (production value is /etc/moha/)
|
$configDir = "./config"; // default config dir (production value is /etc/moha/)
|
||||||
|
$httpServerIp = "192.168.1.253";
|
||||||
}else
|
}else
|
||||||
{
|
{
|
||||||
$logLevel = INFO | NOTICE | WARNING | ERROR | ALERT;
|
$logLevel = DEBUG | INFO | NOTICE | WARNING | ERROR | ALERT;
|
||||||
$mqttServerIp = "127.0.0.1"; // IP address of mqttserver in production mode
|
$mqttServerIp = "127.0.0.1"; // IP address of mqttserver in production mode
|
||||||
$dataPath = "/usr/share/moha/";
|
$dataPath = "/usr/share/moha/";
|
||||||
$logFile = "/var/log/moha.log"; // Path of log file
|
$logFile = "/var/log/moha.log"; // Path of log file
|
||||||
$configDir = "/etc/moha"; // default config dir (production value is /etc/moha/)
|
$configDir = "/etc/moha"; // default config dir (production value is /etc/moha/)
|
||||||
|
$httpServerIp = "127.0.0.1";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!init()) exit(1);
|
if (!init()) exit(1);
|
||||||
@ -186,7 +188,7 @@ require "class/main.php";
|
|||||||
require "class/db.php";
|
require "class/db.php";
|
||||||
require "class/hook_class.php";
|
require "class/hook_class.php";
|
||||||
require "utils.php";
|
require "utils.php";
|
||||||
require "config/properties2log.php";
|
require $configDir . "/properties2log.php";
|
||||||
require "mqtt_functions.php";
|
require "mqtt_functions.php";
|
||||||
require "events.php";
|
require "events.php";
|
||||||
require "db_functions.php";
|
require "db_functions.php";
|
||||||
|
@ -6,7 +6,7 @@ function messageReceived($message)
|
|||||||
global $topics, $logFh, $devices, $included;
|
global $topics, $logFh, $devices, $included;
|
||||||
$topic = explode ("/", $message->topic);
|
$topic = explode ("/", $message->topic);
|
||||||
$callback = $topics[$topic[0]]->callback;
|
$callback = $topics[$topic[0]]->callback;
|
||||||
//logger(DEBUG, "topic => " . var_export($topic, true), __FILE__ . ":" . __LINE__);
|
logger(DEBUG, "message => " . var_export($message, true), __FILE__ . ":" . __LINE__);
|
||||||
$callback($topic, $message);
|
$callback($topic, $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +51,9 @@ $topics["pws2mqtt"]->callback = function($topic, $message)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//$device = getDeviceByFriendlyname($topicName, $fn, $payloadArray, true);
|
//$device = getDeviceByFriendlyname($topicName, $fn, $payloadArray, true);
|
||||||
|
if (!empty($payloadArray))
|
||||||
|
{
|
||||||
changeDevice($topicName, $fn, $device["device"], $payloadArray);
|
changeDevice($topicName, $fn, $device["device"], $payloadArray);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
|
@ -41,7 +41,7 @@ $topics["zigbee2mqtt"]->callback = function($topic, $message)
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
}elseif (($topic[array_key_last($topic)]) != "get" and ($topic[array_key_last($topic)]) != "set" and $included)
|
}elseif (($topic[array_key_last($topic)]) != "get" and $included)
|
||||||
{
|
{
|
||||||
$topic = explode ("/", $message->topic, 2); // get topic name
|
$topic = explode ("/", $message->topic, 2); // get topic name
|
||||||
$topicName = $topic[0];
|
$topicName = $topic[0];
|
||||||
@ -80,7 +80,7 @@ $topics["zigbee2mqtt"]->callback = function($topic, $message)
|
|||||||
|
|
||||||
}else
|
}else
|
||||||
{
|
{
|
||||||
logger(DEBUG, _("Zigbee2mqtt doing nothing !?"));
|
logger(DEBUG, _("Zigbee2mqtt doing get or set !?"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,50 +1,130 @@
|
|||||||
<?php
|
<?php
|
||||||
|
require_once "events.php";
|
||||||
|
|
||||||
function webDashboard($socket, $n = 0)
|
function webDashboard($socket, $n = 0, $page="/")
|
||||||
{
|
{
|
||||||
global $dashboards, $indexDevices;
|
global $dashboards, $indexDevices;
|
||||||
logger(DEBUG, _("webDashboard function"));
|
logger(DEBUG, _("webDashboard function"));
|
||||||
$response = "";
|
$response = ''; //<form action="action.php" method="get">
|
||||||
|
|
||||||
if(array_key_exists($n, $dashboards))
|
if(array_key_exists($n, $dashboards))
|
||||||
{
|
{
|
||||||
foreach ($dashboards[$n] as $ieeeAddress => $property)
|
foreach ($dashboards[$n] as $array)
|
||||||
{
|
{
|
||||||
$value = $indexDevices[$ieeeAddress]->properties[$property]["value"];
|
print_r($array);
|
||||||
|
$device = $indexDevices[$array[0]];
|
||||||
|
$property = $array[1];
|
||||||
|
$propertyObject = $device->properties[$property];
|
||||||
|
$value = $propertyObject["value"];
|
||||||
if ($value === null)
|
if ($value === null)
|
||||||
{
|
{
|
||||||
$value = "null";
|
$value = "null";
|
||||||
}
|
}
|
||||||
logger(DEBUG, _($indexDevices[$ieeeAddress]->friendlyName . " => " . bool2string($value)));
|
logger(DEBUG, $device->friendlyName . " => " . bool2string(_($value)));
|
||||||
$response .= $indexDevices[$ieeeAddress]->friendlyName . " => " . bool2string($value) . "<br>";
|
$response .= $device->friendlyName . aliases($device->friendlyName, $property) . " => " . bool2string(_($value)) . EOL;
|
||||||
|
if (array_key_exists("access", $propertyObject))
|
||||||
|
{
|
||||||
|
logger(DEBUG, _("Access = ") . $propertyObject["access"], __FILE__ . ":" . __LINE__);
|
||||||
|
if(($propertyObject["access"] & 2))
|
||||||
|
{
|
||||||
|
logger(DEBUG, _("Write Access OK ") . ($propertyObject["access"] & 2), __FILE__ . ":" . __LINE__);
|
||||||
|
$response .= " " . displayChoice($device, $property) . EOL;
|
||||||
|
}
|
||||||
|
if(($propertyObject["access"] & 4))
|
||||||
|
{
|
||||||
|
logger(DEBUG, _("can get value") . ($propertyObject["access"] & 4), __FILE__ . ":" . __LINE__);
|
||||||
|
$response .= ' <input type="button" id="' . $device->topic ."/" . $device->friendlyName . "/" . $propertyObject["name"] . '" value="' . _("Update") . "\" onmouseup=\"getPropertyValue('" . $device->topic . "','" . $propertyObject["name"] . "')\"><br>" . EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}else
|
}else
|
||||||
{
|
{
|
||||||
$response = _("dashboard not found");
|
$response = _("dashboard not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlSend($socket, $response);
|
htmlSend($socket, $response);
|
||||||
}
|
}
|
||||||
|
|
||||||
function webBrowse($socket, $argList)
|
function displayChoice($device, $propertyName)
|
||||||
{
|
{
|
||||||
global $topics, $devices;
|
logger(INFO, _("function displayChoice"), __FILE__ . ":" . __LINE__);
|
||||||
|
$propertyObject = $device->properties[$propertyName];
|
||||||
|
|
||||||
|
if(array_key_exists("unit", $propertyObject))
|
||||||
|
{
|
||||||
|
$unit = $propertyObject["unit"];
|
||||||
|
logger(DEBUG, _("unit = ") . $unit, __FILE__ . ":" . __LINE__);
|
||||||
|
}
|
||||||
|
if (!array_key_exists("type", $propertyObject)) return "";
|
||||||
|
switch ($propertyObject["type"])
|
||||||
|
{
|
||||||
|
case "binary":
|
||||||
|
logger(DEBUG, _("type is binary"), __FILE__ . ":" . __LINE__);
|
||||||
|
$choice["on"] = $propertyObject["value_on"];
|
||||||
|
$choice["off"] = $propertyObject["value_off"];
|
||||||
|
if (array_key_exists("toggle", $propertyObject))
|
||||||
|
{
|
||||||
|
$choice["toggle"] = $propertyObject["toggle"];
|
||||||
|
}
|
||||||
|
$formHTML = mkHTML($device, $propertyName, $choice);
|
||||||
|
break;
|
||||||
|
case "numeric":
|
||||||
|
logger(DEBUG, _("type is numeric"), __FILE__ . ":" . __LINE__);
|
||||||
|
$formHTML = '<input type="range" id="' . $propertyObject["name"] . '"';
|
||||||
|
$formHTML .= ' name="' . $propertyObject["name"] . '"';
|
||||||
|
$formHTML .= ' min="' . $propertyObject["value_min"] . '"';
|
||||||
|
$formHTML .= ' max="' . $propertyObject["value_max"] . '"';
|
||||||
|
$formHTML .= ' value="' . $propertyObject["value"] . '"';
|
||||||
|
|
||||||
|
if (array_key_exists("value_step", $propertyObject))
|
||||||
|
{
|
||||||
|
$formHTML .= ' step="' . $propertyObject["value_step"] . '"';
|
||||||
|
}
|
||||||
|
$formHTML .= " onchange=\"setPropertyValue('" . $device->topic . "', this.value, '" . $propertyObject["name"] . "')\">";
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "enum":
|
||||||
|
logger(DEBUG, _("type is enum"), __FILE__ . ":" . __LINE__);
|
||||||
|
$choice = $propertyObject["values"];
|
||||||
|
$formHTML = mkHTML($device, $propertyName, $choice);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return $formHTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mkHTML($device, $propertyName, $choice)
|
||||||
|
{
|
||||||
|
global $listenPort, $httpServerIp;
|
||||||
|
$html = "";
|
||||||
|
logger(DEBUG, _("function mkHTML"), __FILE__ . ":" . __LINE__);
|
||||||
|
foreach ($choice as $key => $value)
|
||||||
|
{
|
||||||
|
$html .= '<input type="button" id="' . $device->topic ."/" . $device->friendlyName . "/" . $propertyName . "/" . $key . '" value="' . $value . "\" onmouseup=\"setPropertyValue('" . $device->topic . "', '" . $value . "', '" . $propertyName . "')\">";
|
||||||
|
}
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function webBrowse($socket, $argList, $page="/browse")
|
||||||
|
{
|
||||||
|
global $topics, $devices, $listenPort,$indexDevices;
|
||||||
logger(DEBUG, _("Generic response to choose device and property"), __FILE__ . ":" . __LINE__);
|
logger(DEBUG, _("Generic response to choose device and property"), __FILE__ . ":" . __LINE__);
|
||||||
//$response = "<html><header></header><body>" . _("unknown command") . "</body></html>";
|
//$response = "<html><header></header><body>" . _("unknown command") . "</body></html>";
|
||||||
$response = "";
|
$response = "";
|
||||||
$flag = false;
|
$flag = false;
|
||||||
$tab = "";
|
$tab = "";
|
||||||
|
|
||||||
if (array_key_exists("topic", $argList))
|
if (array_key_exists("topic", $argList))
|
||||||
{
|
{
|
||||||
if (array_key_exists($argList["topic"], $topics))
|
if (array_key_exists($argList["topic"], $topics))
|
||||||
{
|
{
|
||||||
logger(DEBUG, _("Topic exists") , __FILE__ . ":" . __LINE__);
|
logger(DEBUG, _("Topic exists: ") . $argList["topic"] , __FILE__ . ":" . __LINE__);
|
||||||
$topicRef = '<a href="/?browse&topic=' . htmlentities($argList["topic"]);
|
$topicRef = '<a href="/browse&topic=' . htmlentities($argList["topic"]);
|
||||||
if (array_key_exists("fn", $argList))
|
if (array_key_exists("fn", $argList))
|
||||||
{
|
{
|
||||||
logger(DEBUG, _("FriendlyName exists: ") . $argList["fn"] , __FILE__ . ":" . __LINE__);
|
logger(DEBUG, _("FriendlyName exists: ") . $argList["fn"] , __FILE__ . ":" . __LINE__);
|
||||||
$fn = "";
|
$fn = "";
|
||||||
$fnArray = explode("/", $argList["fn"]);
|
$fnArray = explode("/", $argList["fn"]);
|
||||||
$device = $devices[$argList["topic"]];
|
$device = $devices[$argList["topic"]];
|
||||||
|
|
||||||
//var_dump($fnArray);
|
//var_dump($fnArray);
|
||||||
foreach($fnArray as $value)
|
foreach($fnArray as $value)
|
||||||
{
|
{
|
||||||
@ -64,16 +144,53 @@ function webBrowse($socket, $argList)
|
|||||||
$device = $device["device"];
|
$device = $device["device"];
|
||||||
$fn .= "device/" . $fn;
|
$fn .= "device/" . $fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_a($device, "device"))
|
if (is_a($device, "device"))
|
||||||
{
|
{
|
||||||
|
$response .= '<script language="javascript">
|
||||||
|
<!--
|
||||||
|
function setPropertyValue(topic, value, property)
|
||||||
|
{
|
||||||
|
let xhr = new XMLHttpRequest();
|
||||||
|
xhr.open("GET", "http://192.168.1.253:' . $listenPort . '/set&fn=' . $device->friendlyName . '&property="+property+"&topic="+topic+"&value="+value);
|
||||||
|
xhr.onload = function () {};
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPropertyValue(topic,property)
|
||||||
|
{
|
||||||
|
let xhr = new XMLHttpRequest();
|
||||||
|
xhr.open("GET", "http://192.168.1.253:' . $listenPort . '/get&fn=' . $device->friendlyName . '&property="+property+"&topic="+topic );
|
||||||
|
xhr.onload = function () {};
|
||||||
|
xhr.send();
|
||||||
|
setTimeout(function()
|
||||||
|
{
|
||||||
|
location.reload();
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
// -->
|
||||||
|
</script>';
|
||||||
foreach($device->properties as $key => $value)
|
foreach($device->properties as $key => $value)
|
||||||
{
|
{
|
||||||
$response .= $key . "<br>";
|
$response .= $key . " ";
|
||||||
$response .= $tab . "[<br>";
|
if (array_key_exists("access", $value))
|
||||||
echo memory_get_usage();
|
{
|
||||||
|
if(($value["access"] & 2))
|
||||||
|
{
|
||||||
|
logger(DEBUG, _("Write Access OK ") . ($value["access"] & 2), __FILE__ . ":" . __LINE__);
|
||||||
|
$response .= displayChoice($device, $key);
|
||||||
|
}
|
||||||
|
if(($value["access"] & 4))
|
||||||
|
{
|
||||||
|
logger(DEBUG, _("can get value") . ($value["access"] & 4), __FILE__ . ":" . __LINE__);
|
||||||
|
$response .= ' <input type="button" id="' . $device->topic ."/" . $device->friendlyName . "/" . $key . '" value="' . _("Update") . "\" onmouseup=\"getPropertyValue('" . $device->topic . "', '" . $key . "')\">";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$response .= "<br>\n" . $tab . "[<br>\n";
|
||||||
|
//echo memory_get_usage();
|
||||||
//$response = value($key, $value, $response);
|
//$response = value($key, $value, $response);
|
||||||
iterateProperty($key, $value, $response, $tab);
|
iterateProperty($device, $key, $value, $response, $tab);
|
||||||
$response .= $tab . "]<br>";
|
$response .= $tab . "]<br>\n";
|
||||||
}
|
}
|
||||||
/*foreach($device->properties as $key => $value)
|
/*foreach($device->properties as $key => $value)
|
||||||
{
|
{
|
||||||
@ -86,19 +203,25 @@ function webBrowse($socket, $argList)
|
|||||||
$response .= $topicRef . htmlentities("&fn=" . $fn . "/" . $key) . '">' . $key . "</a><br>\n";
|
$response .= $topicRef . htmlentities("&fn=" . $fn . "/" . $key) . '">' . $key . "</a><br>\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger(DEBUG, _("response: ") . EOL . $response , __FILE__ . ":" . __LINE__);
|
//logger(DEBUG, _("response: ") . EOL . $response , __FILE__ . ":" . __LINE__);
|
||||||
|
|
||||||
//htmlSend($socket, $response);
|
//htmlSend($socket, $response);
|
||||||
}else
|
}else
|
||||||
|
{
|
||||||
|
logger(DEBUG, _("no FriendlyName given"), __FILE__ . ":" . __LINE__);
|
||||||
|
if (empty($devices[$argList["topic"]]))
|
||||||
|
{
|
||||||
|
$response .= _("No devices yet found");
|
||||||
|
}else
|
||||||
{
|
{
|
||||||
foreach($devices[$argList["topic"]] as $key => $value)
|
foreach($devices[$argList["topic"]] as $key => $value)
|
||||||
{
|
{
|
||||||
print "key = " . print_r($key, true) . " value = " . print_r($value, true) . EOLR;
|
//print "key = " . print_r($key, true) . " value = " . print_r($value, true) . EOL;
|
||||||
logger(DEBUG, _("devices de topic: ") . $key , __FILE__ . ":" . __LINE__);
|
logger(DEBUG, _("devices de topic: ") . $key , __FILE__ . ":" . __LINE__);
|
||||||
$response .= $topicRef . htmlentities("&fn=" . $key) . '">' . $key . "</a><br>";
|
$response .= $topicRef . htmlentities("&fn=" . $key) . '">' . $key . "</a><br>\n";
|
||||||
logger(DEBUG, _("response: ") . $response , __FILE__ . ":" . __LINE__);
|
logger(DEBUG, _("response: ") . $response , __FILE__ . ":" . __LINE__);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}else
|
}else
|
||||||
{
|
{
|
||||||
$response = webListTopics();
|
$response = webListTopics();
|
||||||
@ -110,22 +233,28 @@ function webBrowse($socket, $argList)
|
|||||||
htmlSend($socket, $response);
|
htmlSend($socket, $response);
|
||||||
}
|
}
|
||||||
|
|
||||||
function iterateProperty($property, $value, &$response, $tab="")
|
function iterateProperty($device, $property, $value, &$response, $tab="")
|
||||||
{
|
{
|
||||||
$tab .= " ";
|
$tab .= " ";
|
||||||
if (is_array($value) or is_object($value))
|
if (is_array($value) or is_object($value))
|
||||||
{
|
{
|
||||||
logger(DEBUG, _("is object or array"), __FILE__ . ":" . __LINE__ );
|
logger(DEBUG, _("is array"), __FILE__ . ":" . __LINE__ );
|
||||||
foreach($value as $key => $value2)
|
foreach($value as $key => $value2)
|
||||||
{
|
{
|
||||||
|
|
||||||
logger(DEBUG, $key, __FILE__ . ":" . __LINE__ );
|
logger(DEBUG, $key, __FILE__ . ":" . __LINE__ );
|
||||||
iterateProperty($key, $value2, $response, $tab);
|
$response .= $tab . $key;
|
||||||
|
if (is_array($value2) or is_object($value2))
|
||||||
|
{
|
||||||
|
$response .= "<br>\n";
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
$response .= " = ";
|
||||||
|
}
|
||||||
|
iterateProperty($device, $key, $value2, $response, $tab);
|
||||||
}
|
}
|
||||||
}else
|
}else
|
||||||
{
|
{
|
||||||
$response .= $tab . $property . ' = ' . bool2string($value) . "<br>";//value($property, $value, "");
|
$response .= bool2string($value) . "<br>\n";//. displayChoice($device, $property); //value($property, $value, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +265,7 @@ function webListTopics()
|
|||||||
$response = "";
|
$response = "";
|
||||||
foreach ($topics as $name => $topic)
|
foreach ($topics as $name => $topic)
|
||||||
{
|
{
|
||||||
$response .= '<a href="/?browse&topic=' . $name . '">' . $name ."</a><br>";
|
$response .= '<a href="/browse&topic=' . $name . '">' . $name ."</a><br>\n";
|
||||||
}
|
}
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
@ -162,15 +291,24 @@ function webGet($argList)
|
|||||||
|
|
||||||
function webSet($argList)
|
function webSet($argList)
|
||||||
{
|
{
|
||||||
|
global $indexFriendlyName;
|
||||||
if(!array_key_exists("topic", $argList) or !array_key_exists("fn", $argList) or !array_key_exists("property", $argList) or !array_key_exists("value", $argList))
|
if(!array_key_exists("topic", $argList) or !array_key_exists("fn", $argList) or !array_key_exists("property", $argList) or !array_key_exists("value", $argList))
|
||||||
{
|
{
|
||||||
$response = "SET: " . _("no parameters passed, need topic, fn, property and value") . "passed";
|
if (!array_key_exists($argList["topic"], $topics) )
|
||||||
|
{
|
||||||
|
$response = "SET: " . _("bad parameter passed: topic does not exists") . "<br>\n";
|
||||||
|
}
|
||||||
|
if (!array_key_exists(!array_key_exists($argList["fn"], $indexFriendlyName)))
|
||||||
|
{
|
||||||
|
$response = "SET: " . _("bad parameter passed: fn does not exists") . "<br>\n";
|
||||||
|
}
|
||||||
|
$response .= "SET: " . _("not all parameters passed, need topic, fn, property and value");
|
||||||
}else
|
}else
|
||||||
{
|
{
|
||||||
$response = "setting property " . $argList["property"] . " of " . $argList["fn"] . " to value: " . $argList["value"];
|
$response = "setting property " . $argList["property"] . " of " . $argList["fn"] . " to value: " . $argList["value"];
|
||||||
$payload = array($argList["property"] => $argList["value"]);
|
$payload = array($argList["property"] => $argList["value"]);
|
||||||
publish(Z2M . "/" . $argList["fn"], $payload);
|
publish(Z2M . "/" . $argList["fn"], $payload);
|
||||||
|
//removeEvent($indexFriendlyName($argList["fn"]), $argList["property"], "OFF");
|
||||||
}
|
}
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
@ -228,7 +366,7 @@ function webNotify($argList)
|
|||||||
{
|
{
|
||||||
if (!array_key_exists("topic", $argList) or !array_key_exists("fn", $argList) or !array_key_exists("property", $argList) or !array_key_exists("condition", $argList) or !array_key_exists("value", $argList))
|
if (!array_key_exists("topic", $argList) or !array_key_exists("fn", $argList) or !array_key_exists("property", $argList) or !array_key_exists("condition", $argList) or !array_key_exists("value", $argList))
|
||||||
{
|
{
|
||||||
$response = _("Error: With 'notify' command, you need 4 parameters: topic, fn, property, condition, value");
|
$response = _("Error: With 'notify' command, you need 5 parameters: topic, fn, property, condition, value");
|
||||||
}else
|
}else
|
||||||
{
|
{
|
||||||
$response = _("notify command have been set");
|
$response = _("notify command have been set");
|
||||||
|
8
webserver/sendrange.js
Normal file
8
webserver/sendrange.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<script>
|
||||||
|
function sendRange(value, property)
|
||||||
|
{
|
||||||
|
let xhr = new XMLHttpRequest();
|
||||||
|
xhr.open("GET", "http://localhost:' . $listenPort . '/set&fn=' . $device->friendlyName . '&property="+property+"&topic=' . $device->topic . '&value=" + value);
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
<script>
|
@ -11,22 +11,23 @@ $listenHost = "0.0.0.0";
|
|||||||
$listenPort = 1025;
|
$listenPort = 1025;
|
||||||
$Dashboards = array();
|
$Dashboards = array();
|
||||||
|
|
||||||
|
require_once $configDir . "/aliases.php";
|
||||||
require_once $configDir . "/dashboard_conf.php";
|
require_once $configDir . "/dashboard_conf.php";
|
||||||
require_once "class/main.php";
|
require_once "class/main.php";
|
||||||
require "webserver/cmd_functions.php";
|
require_once "webserver/cmd_functions.php";
|
||||||
|
|
||||||
// opening listening server
|
// opening listening server
|
||||||
$socket = stream_socket_server("tcp://" . $listenHost . ":" . $listenPort, $error_code, $error_message) or logger(ERROR, _("Could not create socket"), __FILE__ . ":" . __LINE__);
|
$socket = stream_socket_server("tcp://" . $listenHost . ":" . $listenPort, $error_code, $error_message) or logger(ERROR, _("Could not create socket"), __FILE__ . ":" . __LINE__);
|
||||||
stream_set_blocking($socket, false);
|
stream_set_blocking($socket, false);
|
||||||
$read = array( $socket );
|
$read = array( $socket );
|
||||||
|
|
||||||
function htmlSend($socket, $text)
|
function htmlSend($socket, $text, $meta="")
|
||||||
{
|
{
|
||||||
$httpHeader = "HTTP/1.1 200 OK" . EOLR .
|
$httpHeader = "HTTP/1.1 200 OK" . EOLR .
|
||||||
"Date: " . date("r") . EOLR .
|
"Date: " . date("r") . EOLR .
|
||||||
"Connection: close" . EOLR .
|
"Connection: close" . EOLR .
|
||||||
"Content-Type: text/html; charset=UTF-8" . EOLR . EOLR;
|
"Content-Type: text/html; charset=UTF-8" . EOLR . EOLR;
|
||||||
$response = $httpHeader . '<!doctype html>' . EOL . '<html lang="fr">' . EOL . '<head>' . EOL . '<meta charset="utf-8">' . EOL . '<title>Moha</title>' . EOL . '</head><body>' . $text . "</body></html>";
|
$response = $httpHeader . '<!doctype html>' . EOL . '<html lang="fr">' . EOL . '<head>' . EOL . $meta . EOL . '<meta charset="utf-8">' . EOL . '<title>Moha</title>' . EOL . '</head><body>' . EOL . $text . "</body></html>";
|
||||||
|
|
||||||
stream_socket_sendto($socket, $response);
|
stream_socket_sendto($socket, $response);
|
||||||
}
|
}
|
||||||
@ -47,6 +48,7 @@ function askWebServer($read)
|
|||||||
$input = fgets($spawn, 4096);
|
$input = fgets($spawn, 4096);
|
||||||
logger(DEBUG, $input, __FILE__ . ":" . __LINE__);
|
logger(DEBUG, $input, __FILE__ . ":" . __LINE__);
|
||||||
$input = substr($input,5);
|
$input = substr($input,5);
|
||||||
|
$page = $input;
|
||||||
$input = explode(" ", $input); // suppress text
|
$input = explode(" ", $input); // suppress text
|
||||||
if (!empty($input[0]))
|
if (!empty($input[0]))
|
||||||
{
|
{
|
||||||
@ -64,6 +66,7 @@ function askWebServer($read)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger(DEBUG, print_r($argList, true), __FILE__ . ":" . __LINE__);
|
logger(DEBUG, print_r($argList, true), __FILE__ . ":" . __LINE__);
|
||||||
|
|
||||||
if(array_key_exists("cmd", $argList))
|
if(array_key_exists("cmd", $argList))
|
||||||
{
|
{
|
||||||
$command = strtolower($argList["cmd"]);
|
$command = strtolower($argList["cmd"]);
|
||||||
@ -71,11 +74,11 @@ function askWebServer($read)
|
|||||||
switch($command)
|
switch($command)
|
||||||
{
|
{
|
||||||
case "dashboard":
|
case "dashboard":
|
||||||
webDashboard($spawn, $argList["dashboard"]);
|
webDashboard($spawn, $argList["dashboard"], $argList["page"]);
|
||||||
break;
|
break;
|
||||||
case "browse":
|
case "browse":
|
||||||
logger(DEBUG, _("Browsing"), __FILE__ . ":" . __LINE__);
|
logger(DEBUG, _("Browsing"), __FILE__ . ":" . __LINE__);
|
||||||
webBrowse($spawn, $argList);
|
webBrowse($spawn, $argList, $argList["page"]);
|
||||||
//return true;
|
//return true;
|
||||||
break;
|
break;
|
||||||
case "get":
|
case "get":
|
||||||
@ -97,7 +100,15 @@ function askWebServer($read)
|
|||||||
logger(DEBUG, print_r($monitored, true), __FILE__ . ":" . __LINE__);
|
logger(DEBUG, print_r($monitored, true), __FILE__ . ":" . __LINE__);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
webBrowse($spawn, $argList);
|
if (is_numeric(array_key_first($argList)))
|
||||||
|
{
|
||||||
|
webDashboard($spawn, $argList[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (array_key_exists("page", $argList))
|
||||||
|
{
|
||||||
|
htmlSend($spawn, '<meta http-equiv="refresh" content="1; URL=' . $argList["page"] . '" />');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}else
|
}else
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user