diff --git a/src/common/config/is_pwa.js b/src/common/config/is_pwa.js
new file mode 100644
index 0000000000..a833b53a08
--- /dev/null
+++ b/src/common/config/is_pwa.js
@@ -0,0 +1,4 @@
+/** Return if the displaymode is in standalone mode (PWA). */
+export default function isPwa() {
+ return (window.matchMedia('(display-mode: standalone)').matches);
+}
diff --git a/src/panels/config/zwave/zwave-log-dialog.js b/src/panels/config/zwave/zwave-log-dialog.js
new file mode 100644
index 0000000000..753dc869b4
--- /dev/null
+++ b/src/panels/config/zwave/zwave-log-dialog.js
@@ -0,0 +1,78 @@
+import '@polymer/paper-dialog-scrollable/paper-dialog-scrollable.js';
+import '@polymer/paper-dialog/paper-dialog.js';
+import { html } from '@polymer/polymer/lib/utils/html-tag.js';
+import { PolymerElement } from '@polymer/polymer/polymer-element.js';
+
+import '../../../resources/ha-style.js';
+
+import EventsMixin from '../../../mixins/events-mixin.js';
+
+class ZwaveLogDialog extends EventsMixin(PolymerElement) {
+ static get template() {
+ return html`
+
+
+ OpenZwave internal logfile
+
+ [[_ozwLog]]
+
+
+ `;
+ }
+
+ static get properties() {
+ return {
+ hass: Object,
+ _ozwLog: String,
+
+ _dialogClosedCallback: Function,
+
+ _opened: {
+ type: Boolean,
+ value: false,
+ },
+
+ _intervalId: String,
+
+ _numLogLines: {
+ type: Number
+ }
+ };
+ }
+
+ ready() {
+ super.ready();
+ this.addEventListener('iron-overlay-closed', ev => this._dialogClosed(ev));
+ }
+
+ showDialog({ _ozwLog, hass, _tail, _numLogLines, dialogClosedCallback }) {
+ this.hass = hass;
+ this._ozwLog = _ozwLog;
+ this._opened = true;
+ this._dialogClosedCallback = dialogClosedCallback;
+ this._numLogLines = _numLogLines;
+ setTimeout(() => this.$.pwaDialog.center(), 0);
+ if (_tail) {
+ this.setProperties({
+ _intervalId: setInterval(() => { this._refreshLog(); }, 1500) });
+ }
+ }
+
+ async _refreshLog() {
+ const info = await this.hass.callApi('GET', 'zwave/ozwlog?lines=' + this._numLogLines);
+ this.setProperties({ _ozwLog: info });
+ }
+
+ _dialogClosed(ev) {
+ if (ev.target.nodeName === 'ZWAVE-LOG-DIALOG') {
+ clearInterval(this._intervalId);
+ this._opened = false;
+ const closedEvent = true;
+ this._dialogClosedCallback({ closedEvent });
+ this._dialogClosedCallback = null;
+ }
+ }
+}
+
+customElements.define('zwave-log-dialog', ZwaveLogDialog);
diff --git a/src/panels/config/zwave/zwave-log.js b/src/panels/config/zwave/zwave-log.js
index 712c9d7fab..5cf7e84bdc 100644
--- a/src/panels/config/zwave/zwave-log.js
+++ b/src/panels/config/zwave/zwave-log.js
@@ -2,12 +2,18 @@ import '@polymer/paper-button/paper-button.js';
import '@polymer/paper-card/paper-card.js';
import '@polymer/paper-checkbox/paper-checkbox.js';
import '@polymer/paper-input/paper-input.js';
+import '@polymer/paper-dialog/paper-dialog.js';
+import '@polymer/paper-dialog-scrollable/paper-dialog-scrollable.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
+import EventsMixin from '../../../mixins/events-mixin.js';
+import isPwa from '../../../common/config/is_pwa.js';
import '../ha-config-section.js';
-class OzwLog extends PolymerElement {
+let registeredDialog = false;
+
+class OzwLog extends EventsMixin(PolymerElement) {
static get template() {
return html`