Skip to content

Commit

Permalink
Merge pull request #708 from Martin-Gleiss/develop
Browse files Browse the repository at this point in the history
Release v3.2.1
  • Loading branch information
wvhn authored Feb 14, 2022
2 parents 67e67b0 + 8b8a11e commit 2e5f437
Show file tree
Hide file tree
Showing 29 changed files with 470 additions and 537 deletions.
35 changes: 35 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,38 @@
## 3.2.1
### New / Changed Widgets

### Other New Features
- page "driver_debug" for visualizing communication parameters. Good if browser tools are not available, e.g. on smartphones
- phone widget widget displays callees image on outgoing calls and accepts images also with callers / callees names

### Improvements
- docu for image displaying widgets improved (multimedia.widget, basic.print)
- basic.windows takes 'closed', 'tilted' and 'open' as arguments, as frequently used in fhem. example3.graphic widgets also updated.

### Updated Libraries

### Deprecated

### Removed Features

### Fixed Bugs
- menu item "smarthomeNG" got lost if new smarthomeNG driver was selected
- calendars with names containing whitespaces were not loaded (since at least v2.9)
- smarthomeNG new driver did not work on old browsers (javascript replaceAll() function not available)
- mixing autogenerated pages from smarthomeNG with own pages did not work with the new smarthomeNG driver
- menus in config page did not show as dialogs if screen was too small (e.g. split w/ browser tools)
- config page did not work if ./dropins/lang folder was missing
- cache folders were not created separately for different devices. This caused CSS mix if cache was activated and differnet designs were configured
- on iOS9 the UZSU widgets did not run and even prevented smartVISU from starting if cache was activated
- new smarthomeng.js driver did not work if a port was provided in the URL
- device.uzsutable did not run on iOS9 devices (even after general uzsu fix)
- offline driver stopped working on large number of items (php request overflow)
- status.activelist did not work correctly if more than one status.activelist was on a page

### Known Bugs
- if item contains a stringified number (e.g. with leading zero). widget.set converts it back to numeric format - so basic.print can not print it as text


## 3.2.0
### New / Changed Widgets
- basic.window and device.window provide an additional color mode: icon0 if closed / custom color if open
Expand Down
19 changes: 15 additions & 4 deletions driver/io_offline.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,11 +191,9 @@ var io = {
},

/**
* Reads all values from bus and refreshes the pages
* Reads limited range of items in order to avoid php request overflow
*/
all: function () {
var items = widget.listeners().join(',');

getSlice: function(items) {
// only if anyone listens
if (items.length) {
$.ajax({ url: 'driver/io_offline.php',
Expand All @@ -218,6 +216,19 @@ var io = {
})
.fail(notify.json)
}
},

/**
* Reads all values from bus and refreshes the pages
*/
all: function() {
var allItems = widget.listeners();
var items;

do {
items = allItems.splice(0,100).join(',');
io.getSlice(items);
} while (allItems.length > 0);

// plots
var repeatSeries = function(item, tmin, tmax, ymin, ymax, cnt, step, startval) {
Expand Down
26 changes: 13 additions & 13 deletions driver/io_smarthomeng.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* @default driver_port 2424
* @default driver_tlsport 2425
* @hide reverseproxy
* @hide driver_realtime
* @hide driver_realtime
* @hide driver_ssl
* @hide driver_username
* @hide driver_password
Expand Down Expand Up @@ -74,8 +74,8 @@ var io = {

// if user-called host is not an IP v4 address check if called host is internal hostname of smartVISU server
// otherwise assume that call comes from external and then empty io.address
if (!$.isNumeric(location.host.replaceAll('.',''))){
if ( location.host != sv.config.svHostname )
if (!$.isNumeric(location.hostname.split('.').join(''))) { // replaceAll() does not work for old browsers
if ( location.hostname != sv.config.svHostname )
io.address = '';
}
io.open();
Expand Down Expand Up @@ -140,9 +140,9 @@ var io = {
// use url of current page if not defined
io.address = location.hostname;
}
io.port = ports[protocol];
io.port = ports[protocol];

if (!io.port) {
if (!io.port) { // is still undefined, if io.address was empty at start of io.open
// use port of current page if not defined and needed
if (location.port != '') {
io.port = location.port;
Expand All @@ -157,7 +157,7 @@ var io = {
io.port = ports[io.address.substr(0, io.address.indexOf(':'))+'://'];
}
// DEBUG:
console.log("[io.smarthome.py] opening websocket on "+ protocol + io.address + ':' + io.port);
console.log("[io.smarthomeng] opening websocket on "+ protocol + io.address + ':' + io.port);
io.socket = new WebSocket(protocol + io.address + ':' + io.port);

io.socket.onopen = function () {
Expand All @@ -178,7 +178,7 @@ var io = {
var item, val;
var data = JSON.parse(event.data);
// DEBUG:
console.log("[io.smarthome.py] receiving data: ", event.data);
console.log("[io.smarthomeng] receiving data: ", event.data);

switch (data.cmd) {
case 'item':
Expand Down Expand Up @@ -248,11 +248,11 @@ var io = {

io.socket.onerror = function (error) {
if(io.socketErrorNotification == null || !notify.exists(io.socketErrorNotification))
io.socketErrorNotification = notify.message('error', 'Driver: smarthome.py', 'Could not connect to smarthome.py server!<br /> Websocket error ' + error.data + '.');
io.socketErrorNotification = notify.message('error', 'Driver: smarthomeng', 'Could not connect to smarthomeNG server!<br /> Websocket error ' + error.data + '.');
};

io.socket.onclose = function () {
console.log('[io_smarthome.py]: Connection closed to smarthome.py server!');
console.log('[io_smarthomeng]: Connection closed to smarthomeNG server!');
};
},

Expand All @@ -263,11 +263,11 @@ var io = {
if (io.socket.readyState == 1) {
io.socket.send(unescape(encodeURIComponent(JSON.stringify(data))));
// DEBUG:
console.log('[io.smarthome.py] sending data: ', JSON.stringify(data));
console.log('[io.smarthomeng] sending data: ', JSON.stringify(data));
}
else {
// DEBUG:
console.log('[io.smarthome.py] web socket not ready: ', JSON.stringify(data));
console.log('[io.smarthomeng] web socket not ready: ', JSON.stringify(data));
if (data.cmd == 'logic') io.triggerqueue.push(JSON.stringify(data));
};
},
Expand Down Expand Up @@ -298,7 +298,7 @@ var io = {
sendqueue: function () {
while (io.triggerqueue.length > 0) {
// DEBUG:
console.log('[io.smarthome.py] send from queue: ', io.triggerqueue[0]);
console.log('[io.smarthomeng] send from queue: ', io.triggerqueue[0]);
io.socket.send(io.triggerqueue.shift());
}
},
Expand Down Expand Up @@ -342,7 +342,7 @@ var io = {
* Closes the connection
*/
close: function () {
console.log("[io.smarthome.py] close connection");
console.log("[io.smarthomeng] close connection");

if (io.socket.readyState > 0) {
io.socket.close();
Expand Down
2 changes: 1 addition & 1 deletion index.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@

// add smarthome dir if it is not directly chosen.
// allows combination of custom pages with auto-generated pages from smarthomeNG
if (config_driver == 'smarthome.py' and $actual_pages != 'smarthome' and is_dir(const_path."pages/smarthome"))
if (substr(config_driver, 0, 9) == 'smarthome' and $actual_pages != 'smarthome' and is_dir(const_path."pages/smarthome"))
$loader->addPath(const_path.'pages/smarthome');

// make sure SV doesn't load stuff from dropins unless pages are configured
Expand Down
2 changes: 1 addition & 1 deletion lib/base/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -1795,7 +1795,7 @@ $(document).on('pagecontainerchange', function(event, ui) {
.end().each(function(){ // block browser back / foreward buttons
var currentURL = $(this).context.baseURI;
$(document).on("pagecontainerbeforechange", function (e, data) {
if (typeof data.toPage == "string" && data.prevPage != undefined ) {
if (typeof data.toPage == "string" && data.prevPage != undefined && data.options.role != "popup" && data.options.role != "dialog" && data.options.direction != "back") {
data.toPage = currentURL;
history.pushState(null,'',currentURL);
console.log(currentURL + ': clear history in order to block the back / forward buttons');
Expand Down
2 changes: 1 addition & 1 deletion lib/calendar/calendar.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public function init($request)
if(isset($request['count']))
$this->count = $request['count'];
if(isset($request['calendar']))
$this->calendar_names = preg_split('/[\s,]+/m', strtolower($request['calendar']));
$this->calendar_names = preg_split('/,\s/m', strtolower($request['calendar']));
$this->url = config_calendar_url;
}

Expand Down
28 changes: 8 additions & 20 deletions lib/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,6 @@ public function get($source = 'all')
case 'globalonly':
if (is_file(const_path.'config.ini'))
$config = parse_ini_file(const_path.'config.ini', true, self::INI_SCANNER);

//drop support for legacy config.php as of v3.1
//
//elseif (is_file(const_path.'config.php')) {
// read legacy config.php
// $configphp = file_get_contents(const_path.'config.php');
// preg_match_all("/define\s*\s*\('config_(.*?)'\s*,\s*(.*)\s*\)\s*;\s*[\r\n]+/", $configphp, $matches, PREG_SET_ORDER);

// $config = array();
// foreach($matches as $match) {
// $config[$match[1]] = eval('return '.$match[2].';');
// }
//}
break;

// configuration per pages (config.ini in current pages folder)
Expand Down Expand Up @@ -124,18 +111,19 @@ public function save($target, $options, $pages) {
break;
case 'cookie':
$basepath = substr(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), 0, -strlen(substr($_SERVER['SCRIPT_FILENAME'], strlen(const_path))));
if (isset($config['cache'])) {
// generate unique cache folder for cookie (combination of remote IP, forwarded IP and time should be unique)
if(!isset($config['cachefolder']) || $config['cachefolder'] == 'global')
$config['cachefolder'] = md5($_SERVER['REMOTE_ADDR'] . ($_SERVER['HTTP_CLIENT_IP'] ?: $_SERVER['HTTP_X_FORWARDED_FOR'] ?: $_SERVER['HTTP_X_FORWARDED'] ?: $_SERVER['HTTP_FORWARDED_FOR'] ?: $_SERVER['HTTP_FORWARDED']) . time());
} else
unset($config['cachefolder']);


if(count($config) > 0){ // some options are set
foreach ($config as $key=>&$val) {
$val = ($val == "true") ? "1" : $val;
$val = ($val == "false") ? "" : $val;
}
// generate unique cache folder for cookie (combination of remote IP, forwarded IP and time should be unique) - in case cache is activated globally
if(!isset($config['cachefolder']) || $config['cachefolder'] == 'global'){
$clientIP = (((((isset($_SERVER['HTTP_CLIENT_IP']) && $_SERVER['HTTP_CLIENT_IP'] ? $_SERVER['HTTP_CLIENT_IP']: isset($_SERVER['HTTP_X_FORWARDED_FOR']) &&$_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] :
isset($_SERVER['HTTP_X_FORWARDED']) && $_SERVER['HTTP_X_FORWARDED']) ? $_SERVER['HTTP_X_FORWARDED']: isset($_SERVER['HTTP_FORWARDED_FOR']) && $_SERVER['HTTP_FORWARDED_FOR']) ? $_SERVER['HTTP_FORWARDED_FOR'] :
isset($_SERVER['HTTP_FORWARDED']) && $_SERVER['HTTP_FORWARDED']) ? $_SERVER['HTTP_FORWARDED']:'');
$config['cachefolder'] = md5($_SERVER['REMOTE_ADDR'] . $clientIP . time());
}
$confexpire = time()+3600*24*364*10; // expires after 10 years
$success = setcookie('config', json_encode($config), ['expires' => $confexpire, 'path' => $basepath, 'samesite' => 'Lax']);
}
Expand Down
20 changes: 11 additions & 9 deletions lib/phone/phone.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,6 @@ public function prepare()
{
// date
$ds['date'] = transdate('short', strtotime($ds['date']));

// is there a picture to the caller?
if ($ds['number'] != '' and is_file(const_path.'pics/phone/'.$ds['number'].'.jpg'))
$ds['pic'] = $ds['number'].'.jpg';
elseif ($ds['number'] != '' and is_file(const_path.'pics/phone/'.$ds['number'].'.png'))
$ds['pic'] = $ds['number'].'.png';
else
$ds['pic'] = '0.jpg';

$ds['text'] = $ds['name'];

// no name? caller unknown
Expand Down Expand Up @@ -95,6 +86,17 @@ public function prepare()
if ($ds['called'] !='')
$ds['number'] = $ds['called'];
}
// is there a picture to the caller?
if ($ds['number'] != '' and is_file(const_path.'pics/phone/'.$ds['number'].'.jpg'))
$ds['pic'] = $ds['number'].'.jpg';
elseif ($ds['number'] != '' and is_file(const_path.'pics/phone/'.$ds['number'].'.png'))
$ds['pic'] = $ds['number'].'.png';
elseif ($ds['name'] != '' and is_file(const_path.'pics/phone/'.$ds['name'].'.jpg'))
$ds['pic'] = $ds['name'].'.jpg';
elseif ($ds['name'] != '' and is_file(const_path.'pics/phone/'.$ds['name'].'.png'))
$ds['pic'] = $ds['name'].'.png';
else
$ds['pic'] = '0.jpg';

$ret[] = $ds;
}
Expand Down
3 changes: 2 additions & 1 deletion pages/base/config.html
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ <h3>{{ lang('configuration_page', 'interface', 'label') }}</h3>
]
) }}
{{ forms.config_input(source, values, 'title') }}
{{ forms.config_select(source, values, 'lang', dir('lang', '^(.*?)\.ini$')|merge(dir('dropins/lang', '^(.*?)\.ini$')) ) }}
{% set langdir = dir('lang', '^(.*?)\.ini$') %} {% if isdir('dropins/lang') %} {% set langdir = langdir|merge(dir('dropins/lang', '^(.*?)\.ini$')) %} {% endif %}
{{ forms.config_select(source, values, 'lang', langdir ) }}
{{ forms.config_flip(source, values, 'cache', '<button type="button" data-theme="a" data-icon="delete" data-inline="true" id="clear_cache' ~ id ~ '" class="ui-micro"' ~ (not values[source]['cache'] is defined ? ' disabled="disabled"'|raw) ~ '>' ~ lang('configuration_page', 'cache', 'clearbutton') ~'</button>') }}
{{ forms.check_cache ( source, values, 'cache') }}
</div>
Expand Down
61 changes: 61 additions & 0 deletions pages/base/driver_debug.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* -----------------------------------------------------------------------------
* @package smartVISU
* @author Wolfram v. Hülsen
* @copyright 2022
* @license GPL [http://www.gnu.de]
* -----------------------------------------------------------------------------
*/

/** visualizes the most relevant parameters of the websocekt connection
* good e.g. on smartphones where no browser console is available
*/

{% extends "rooms.html" %}

{% block content %}
<h1>Display Connection Details</h1>

<h2>Configuration Parameters</h2>
<ul>
<li>driver name:&nbsp;&nbsp; <span id="line1"></span></li>
<li>sv.driver.address:&nbsp;&nbsp;<span id="line2"></span></li>
<li>sv.config.driver.port:&nbsp;&nbsp; <span id="line3"></span></li>
<li>sv.config.driver.tlsport:&nbsp;&nbsp; <span id="line4"></span></li>
<li>sv.config.svHostname:&nbsp;&nbsp; <span id="line5"></span></li>

</ul>
<h2>Location Info</h2>
<ul>
<li>location.host:&nbsp;&nbsp; <span id="line6"></span></li>
<li>location.hostname:&nbsp;&nbsp; <span id="line7"></span></li>
<li>location.protocol:&nbsp;&nbsp;<span id="line8"></span></li>
</ul>

<h2>Websocket Parameters</h2>
<ul>
<li>io.address:&nbsp;&nbsp; <span id="line9"></span></li>
<li>io.port:&nbsp;&nbsp; <span id="line10"></span></li>
<li>Websocket URL:&nbsp;&nbsp; <span id="line11"></span></li>
</ul>

<span id="line12"></span><br />
<span id="line13"></span><br />

<script>
$('#line1').text(sv.config.driver.name);
$('#line2').text(sv.config.driver.address);
$('#line3').text(sv.config.driver.port);
$('#line4').text(sv.config.driver.tlsport);
$('#line5').text(sv.config.svHostname);
$('#line6').text(location.host);
$('#line7').text(location.hostname);
$('#line8').text(location.protocol);
$('#line9').text(io.address);
$('#line10').text(io.port);
$('#line11').text(io.socket.url);

</script>


{% endblock %}
2 changes: 1 addition & 1 deletion pages/base/system_menu.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ <h3>Widget Assistant</h3>
</li>


{% if config_driver == 'smarthome.py' %}
{% if config_driver == 'smarthome.py' or config_driver == 'smarthomeng' %}
<li data-icon="false">
<a href="index.php?page=smarthomeNG">
<img class="icon" src="{{ icon0 }}logo_smarthomeNG.svg" alt="SmartHomeNG" />
Expand Down
4 changes: 2 additions & 2 deletions pages/base/templatechecker.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<h1>Template Checker</h1>
<form>
{{ forms.config_select('tplchk', { 'tplchck': {'pages': config_pages }}, 'pages', dir('pages', '^(?!base|apps)(.+?)') ) }}
{{ forms.config_select('tplchk', { 'tplchk': {'pages': config_pages }}, 'pages', dir('pages', '^(?!base|apps)(.+?)') ) }}
<label><input name="checkbox-0 " type="checkbox" id="tplchk_chk_errors_only">Show warnings/errors only</label>
<label><input name="checkbox-0 " type="checkbox" id="tplchk_chk_subfolders">Don´t check files in subfolders</label>
<div id="chk_items" style="visibility: hidden;">
Expand Down Expand Up @@ -54,4 +54,4 @@ <h2>System checks:</h2>

<h2>Files in template directory:</h2>
<div data-role="collapsible" data-theme="a" data-content-theme="a" class="tplchk_file_list"></div>
{% endblock %}
{% endblock %}
7 changes: 7 additions & 0 deletions pages/docu/basic/widget_basic.print.html
Original file line number Diff line number Diff line change
Expand Up @@ -105,5 +105,12 @@ <h5>Advanced Scripting</h5>
{{ basic.print('', 'bath.value', 'text', '"Content of element is: \'" + $("#otherEl").text() + "\'"') }}
</div>

An image given as Base64-coded data in a text item can be displayed by using
<div class="twig">
<code class="prettyprint">{% filter trim|escape|nl2br %}{% verbatim %}
<img id="myimage" src="" />
{{basic.print('','<item with data>','script','$("#myimage").attr("src", VAR)') }}
{% endverbatim %}{% endfilter %}</code>
</div>

{% endblock %}
Loading

0 comments on commit 2e5f437

Please sign in to comment.