Initial MultiPrinter

pull/125/head
Robert Stein 2020-12-21 09:09:28 +01:00
parent 4688de9aaa
commit 061c92a260
34 changed files with 1972 additions and 1556 deletions

View File

@ -2,7 +2,13 @@
<head>
<link rel="stylesheet" href="https://unpkg.com/carbon-components/css/carbon-components.min.css" ></style>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.1/css/all.css">
<style>.hidden{display:none} .bx--form-item{margin-bottom:20px};</style>
<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js'></script>
<style>.hidden{display:none} .bx--form-item{margin-bottom:20px} .menitem{padding:6px 1rem;font-size:.875rem;font-weight:600;line-height:1.29;letter-spacing:.16px;display:flex;justify-content:space-between;text-decoration:none;color:#c6c6c6}</style>
<style>
</style>
</head>
<body>
<header class="cv-header bx--header">
@ -13,7 +19,9 @@
<nav class="cv-header-nav bx--header__nav"></nav>
<div class="bx--header__global">
<button type="button" class="cv-header-global-action bx--header__action" onclick="openWifiInfo()">
<i class="fas fa-wifi" style="color: white; font-size: 20px;"></i>
<svg focusable="false" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg" fill="currentColor" width="20" height="20" viewBox="0 0 32 32" aria-hidden="true">
<path d="M11,11V21H21V11Zm8,8H13V13h6Z"></path><path d="M30,13V11H26V8a2,2,0,0,0-2-2H21V2H19V6H13V2H11V6H8A2,2,0,0,0,6,8v3H2v2H6v6H2v2H6v3a2,2,0,0,0,2,2h3v4h2V26h6v4h2V26h3a2,2,0,0,0,2-2V21h4V19H26V13ZM24,24H8V8H24Z"></path>
</svg>
</button>
<button type="button" class="cv-header-global-action bx--header__action" onclick="openSidebar()">
<svg focusable="false" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg" fill="currentColor" width="20" height="20" viewBox="0 0 32 32" aria-hidden="true">
@ -23,15 +31,25 @@
</div>
<div aria-hidden="false" id="sidebar" class="cv-header-panel bx--header-panel">
<ul class="cv-switcher bx--switcher__item">
<li class="cv-switcher-item bx--switcher__item"><a class="cv-switcher-item-link bx--switcher__item-link" href="/"><i class="fa fa-home"></i> Home</a></li>
<li class="cv-switcher-item bx--switcher__item"><a class="cv-switcher-item-link bx--switcher__item-link" href="/configure"><i class="fa fa-cog"></i> Configure</a></li>
<li class="cv-switcher-item bx--switcher__item"><a class="cv-switcher-item-link bx--switcher__item-link" href="/configureweather"><i class="fa fa-cloud"></i> Weather</a></li>
<li class="cv-switcher-item bx--switcher__item"><a class="cv-switcher-item-link bx--switcher__item-link" href="/systemreset" onclick="return confirm(&quot;Do you want to reset to default settings?&quot;)"><i class="fa fa-undo"></i> Reset Settings</a></li>
<li class="cv-switcher-item bx--switcher__item"><a class="cv-switcher-item-link bx--switcher__item-link" href="/forgetwifi" onclick="return confirm(&quot;Do you want to forget to WiFi connection?&quot;)"><i class="fa fa-wifi"></i> Forget WiFi</a></li>
<li class="cv-switcher-item bx--switcher__item"><a class="cv-switcher-item-link bx--switcher__item-link" href="/update"><i class="fa fa-wrench"></i> Firmware Update</a></li>
<li class="cv-switcher-item bx--switcher__item"><a class="cv-switcher-item-link bx--switcher__item-link" href="https://github.com/Qrome" target="_blank"><i class="fa fa-question-circle"></i> About</a></li>
<li class="cv-switcher-item bx--switcher__item"><a class="cv-switcher-item-link bx--switcher__item-link menitem" href="/">
Home
<svg focusable="false" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg" fill="currentColor" width="16" height="16" viewBox="0 0 32 32" aria-hidden="true"><path d="M16.6123,2.2138a1.01,1.01,0,0,0-1.2427,0L1,13.4194l1.2427,1.5717L4,13.6209V26a2.0041,2.0041,0,0,0,2,2H26a2.0037,2.0037,0,0,0,2-2V13.63L29.7573,15,31,13.4282ZM18,26H14V18h4Zm2,0V18a2.0023,2.0023,0,0,0-2-2H14a2.002,2.002,0,0,0-2,2v8H6V12.0615l10-7.79,10,7.8005V26Z"></path></svg>
</a></li>
<li class="cv-switcher-item bx--switcher__item"><a class="cv-switcher-item-link bx--switcher__item-link menitem" href="/configure">
Configure
<svg focusable='false' preserveAspectRatio='xMidYMid meet' xmlns='http://www.w3.org/2000/svg' fill='currentColor' width='32' height='32' viewBox='0 0 32 32' aria-hidden='true'><path d='M27,16.76c0-.25,0-.5,0-.76s0-.51,0-.77l1.92-1.68A2,2,0,0,0,29.3,11L26.94,7a2,2,0,0,0-1.73-1,2,2,0,0,0-.64.1l-2.43.82a11.35,11.35,0,0,0-1.31-.75l-.51-2.52a2,2,0,0,0-2-1.61H13.64a2,2,0,0,0-2,1.61l-.51,2.52a11.48,11.48,0,0,0-1.32.75L7.43,6.06A2,2,0,0,0,6.79,6,2,2,0,0,0,5.06,7L2.7,11a2,2,0,0,0,.41,2.51L5,15.24c0,.25,0,.5,0,.76s0,.51,0,.77L3.11,18.45A2,2,0,0,0,2.7,21L5.06,25a2,2,0,0,0,1.73,1,2,2,0,0,0,.64-.1l2.43-.82a11.35,11.35,0,0,0,1.31.75l.51,2.52a2,2,0,0,0,2,1.61h4.72a2,2,0,0,0,2-1.61l.51-2.52a11.48,11.48,0,0,0,1.32-.75l2.42.82a2,2,0,0,0,.64.1,2,2,0,0,0,1.73-1L29.3,21a2,2,0,0,0-.41-2.51ZM25.21,24l-3.43-1.16a8.86,8.86,0,0,1-2.71,1.57L18.36,28H13.64l-.71-3.55a9.36,9.36,0,0,1-2.7-1.57L6.79,24,4.43,20l2.72-2.4a8.9,8.9,0,0,1,0-3.13L4.43,12,6.79,8l3.43,1.16a8.86,8.86,0,0,1,2.71-1.57L13.64,4h4.72l.71,3.55a9.36,9.36,0,0,1,2.7,1.57L25.21,8,27.57,12l-2.72,2.4a8.9,8.9,0,0,1,0,3.13L27.57,20Z'></path><path d='M16,22a6,6,0,1,1,6-6A5.94,5.94,0,0,1,16,22Zm0-10a3.91,3.91,0,0,0-4,4,3.91,3.91,0,0,0,4,4,3.91,3.91,0,0,0,4-4A3.91,3.91,0,0,0,16,12Z'></path></svg>
</a>
</li>
<li class="cv-switcher-item bx--switcher__item"><a class="cv-switcher-item-link bx--switcher__item-link menitem" href="/configureweather"><i class="fa fa-cloud"></i> Weather</a></li>
<li class="cv-switcher-item bx--switcher__item"><a class="cv-switcher-item-link bx--switcher__item-link menitem" href="/systemreset" onclick="return confirm(&quot;Do you want to reset to default settings?&quot;)"><i class="fa fa-undo"></i> Reset Settings</a></li>
<li class="cv-switcher-item bx--switcher__item"><a class="cv-switcher-item-link bx--switcher__item-link menitem" href="/forgetwifi" onclick="return confirm(&quot;Do you want to forget to WiFi connection?&quot;)"><i class="fa fa-wifi"></i> Forget WiFi</a></li>
<li class="cv-switcher-item bx--switcher__item"><a class="cv-switcher-item-link bx--switcher__item-link menitem" href="/update"><i class="fa fa-wrench"></i> Firmware Update</a></li>
<li class="cv-switcher-item bx--switcher__item"><a class="cv-switcher-item-link bx--switcher__item-link menitem" href="https://github.com/Qrome" target="_blank"><i class="fa fa-question-circle"></i> About</a></li>
</ul>
</div>
<!-- <a role="button" tabindex="0" class="Switcher-module--link--3udRg" href="https://ibm.com/brand">IBM Brand Center<svg focusable="false" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg" fill="currentColor" width="16" height="16" viewBox="0 0 32 32" aria-hidden="true"><path d="M24,14H22V8A6,6,0,0,0,10,8v6H8a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H24a2,2,0,0,0,2-2V16A2,2,0,0,0,24,14ZM12,8a4,4,0,0,1,8,0v6H12ZM24,28H8V16H24Z"></path></svg></a> -->
<div class="bx--toast-notification bx--toast-notification--info hidden" style="position: absolute; right: -16px; top: 40px;" id="wifiinfo">
<div class="bx--toast-notification__details">
<h3 class="bx--toast-notification__title">WiFi Signal Strength</h3>
@ -43,7 +61,7 @@
</header>
<div class="bx--grid bx--grid--full-width" style='margin-top:88px'>
<div class="page-header" style="margin-bottom:20px"><h4 class="page-header__label">Configure</h4><h1 id="page-title" class="page-header__title">Station</h1></div>
<div class="page-header" style="margin-bottom:20px"><h4 class="page-header__label">Configure</h4><h1 id="page-title" class="page-header__title">Printer</h1></div>
<div class="bx--row">
<div class="bx--col bx--col--auto bx--data-table-container " data-table>
@ -54,35 +72,106 @@
<section class="bx--table-toolbar ">
<div class="bx--toolbar-content">
<button class="bx--btn bx--btn--sm bx--btn--primary">
<button class="bx--btn bx--btn--sm bx--btn--primary" onclick="openModal('modal-pyu0ribosn')">
Add new
<svg focusable="false" preserveAspectRatio="xMidYMid meet" style="will-change: transform;" xmlns="http://www.w3.org/2000/svg" class="bx--btn__icon" width="20" height="20" viewBox="0 0 32 32" aria-hidden="true"><path d="M17 15L17 7 15 7 15 15 7 15 7 17 15 17 15 25 17 25 17 17 25 17 25 15 17 15z"></path></svg>
</button>
</div>
</section>
<table class="bx--data-table" >
<table class="bx--data-table bx--data-table--visible-overflow-menu" >
<thead>
<tr>
<th class="bx--table-expand"></th>
<th><span class="bx--table-header-label">Name</span></th>
<th><span class="bx--table-header-label">Type</span></th>
<th><span class="bx--table-header-label">Hostname</span></th>
<th><span class="bx--table-header-label">IP</span></th>
<th><span class="bx--table-header-label">State</span></th>
<th><span class="bx--table-header-label">Api Key/User/Password</span></th>
<th class="bx--table-column-menu" style="width: 3.25rem"></th>
</tr>
</thead>
<tbody>
<tr>
<td class="bx--table-expand" data-event="expand">
<button class="bx--table-expand__button">
<svg focusable="false" preserveAspectRatio="xMidYMid meet" style="will-change: transform;" xmlns="http://www.w3.org/2000/svg" class="bx--table-expand__svg" width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"><path d="M11 8L6 13 5.3 12.3 9.6 8 5.3 3.7 6 3z"></path></svg>
</button>
</td>
<td>I3 Mega</td>
<td>Klipper</td>
<td>--</td>
<td>192.168.0.241:7125</td>
<td>Offline</td>
<td>Offline</td>
<!--<td>anycubici3.local</td>
<td>192.168.0.241:7125</td> -->
<td>
<div class="bx--tag bx--tag--magenta">
Offline
</div>
</td>
<!--<td>
<div class="bx--tag bx--tag--cool-gray">
<span class="bx--tag__label">User</span>
<svg width="6px" height="5px" viewBox="0 0 6 5">
<path d="M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z" />
</svg>
</div>
<div class="bx--tag bx--tag--cool-gray">
<span class="bx--tag__label">Password</span>
<svg width="6px" height="5px" viewBox="0 0 6 5">
<path d="M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z" />
</svg>
</div>
</td> -->
<td class="bx--table-column-menu" style="width: 3.25rem">
<div data-overflow-menu role="menu" tabindex="0" aria-label="Overflow menu description" class="bx--overflow-menu">
<div data-overflow-menu role="menu" tabindex="0" class="bx--overflow-menu">
<svg focusable="false" preserveAspectRatio="xMidYMid meet" style="will-change: transform;" xmlns="http://www.w3.org/2000/svg" class="bx--overflow-menu__icon" width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="3" r="1"></circle><circle cx="8" cy="8" r="1"></circle><circle cx="8" cy="13" r="1"></circle></svg>
<ul class="bx--overflow-menu-options bx--overflow-menu--flip" data-floating-menu-direction="bottom">
<li class="bx--overflow-menu-options__option bx--table-row--menu-option">
<button class="bx--overflow-menu-options__btn" onclick="openModal('modal-ed454ftfa4q')">
<div class="bx--overflow-menu-options__option-content">
<svg focusable="false" preserveAspectRatio="xMidYMid meet" style="will-change: transform;" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"><path d="M1 13H15V14H1zM12.7 4.5c.4-.4.4-1 0-1.4 0 0 0 0 0 0l-1.8-1.8c-.4-.4-1-.4-1.4 0 0 0 0 0 0 0L2 8.8V12h3.2L12.7 4.5zM10.2 2L12 3.8l-1.5 1.5L8.7 3.5 10.2 2zM3 11V9.2l5-5L9.8 6l-5 5H3z"></path></svg> Edit
</div>
</button>
</li>
<li class="bx--overflow-menu-options__option bx--table-row--menu-option">
<button class="bx--overflow-menu-options__btn" onclick="openModal('modal-ed454ftfa4q')">
<div class="bx--overflow-menu-options__option-content">
<svg focusable="false" preserveAspectRatio="xMidYMid meet" style="will-change: transform;" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"><path d="M6 6H7V12H6zM9 6H10V12H9z"></path><path d="M2 3v1h1v10c0 .6.4 1 1 1h8c.6 0 1-.4 1-1V4h1V3H2zM4 14V4h8v10H4zM6 1H10V2H6z"></path></svg> Delete
</div>
</button>
</li>
</ul>
</div>
</td>
</tr>
<tr>
<td class="bx--table-expand" data-event="expand">
<button class="bx--table-expand__button">
<svg focusable="false" preserveAspectRatio="xMidYMid meet" style="will-change: transform;" xmlns="http://www.w3.org/2000/svg" class="bx--table-expand__svg" width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"><path d="M11 8L6 13 5.3 12.3 9.6 8 5.3 3.7 6 3z"></path></svg>
</button>
</td>
<td>Anderer</td>
<td>Repetier</td>
<!--<td>--</td>
<td>192.168.0.243:7125</td>-->
<td>
<div class="bx--tag bx--tag--green">
Online
</div>
</td>
<!--<td>
<div class="bx--tag bx--tag--cool-gray">
<span class="bx--tag__label">Key</span>
<svg width="6px" height="5px" viewBox="0 0 6 5">
<path d="M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z" />
</svg>
</div>
</td> -->
<td class="bx--table-column-menu" style="width: 3.25rem">
<div data-overflow-menu role="menu" tabindex="0" class="bx--overflow-menu">
<svg focusable="false" preserveAspectRatio="xMidYMid meet" style="will-change: transform;" xmlns="http://www.w3.org/2000/svg" class="bx--overflow-menu__icon" width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="3" r="1"></circle><circle cx="8" cy="8" r="1"></circle><circle cx="8" cy="13" r="1"></circle></svg>
<ul class="bx--overflow-menu-options bx--overflow-menu--flip" data-floating-menu-direction="bottom">
<li class="bx--overflow-menu-options__option bx--table-row--menu-option">
@ -104,6 +193,8 @@
</div>
</td>
</tr>
</tbody>
</table>
</div>
@ -111,132 +202,155 @@
<script>
function openModal(refelementId) {
document.body.classList.add("bx--body--with-modal-open");
document.getElementById(refelementId).classList.add('is-visible');
}
function closeModal(refelementId) {
document.getElementById(refelementId).classList.remove('is-visible');
document.body.classList.remove("bx--body--with-modal-open");
}
</script>
<form action="/updateweatherconfig" method="get">
<div class="bx--row">
<div class="bx--col bx--col--auto bx--form-item">
<input class="bx--toggle-input bx--toggle-input--small" id="isWeatherEnabled" type="checkbox" name="isWeatherEnabled">
<label class="bx--toggle-input__label" for="isWeatherEnabled"
aria-label="example toggle with state indicator text">
<span class="bx--toggle__switch">
<svg class="bx--toggle__check" width="6px" height="5px" viewBox="0 0 6 5">
<path d="M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z" />
</svg>
<span class="bx--toggle__text--off" aria-hidden="true">Display Weather when printer is off deactivated</span>
<span class="bx--toggle__text--on" aria-hidden="true">Display Weather when printer is off activated</span>
</span>
</label>
</div>
<div data-modal id="modal-pyu0ribosn" class="bx--modal" role="dialog" aria-modal="true" aria-labelledby="modal-pyu0ribosn-label" aria-describedby="modal-pyu0ribosn-heading" tabindex="-1">
<div class="bx--modal-container">
<div class="bx--modal-header">
<p class="bx--modal-header__label bx--type-delta" id="modal-pyu0ribosn-label">Printer Configuration</p>
<p class="bx--modal-header__heading bx--type-beta" id="modal-pyu0ribosn-heading">Create new entry</p>
<button class="bx--modal-close" type="button" onclick="closeModal('modal-pyu0ribosn')">
<svg focusable="false" preserveAspectRatio="xMidYMid meet" style="will-change: transform;" xmlns="http://www.w3.org/2000/svg" class="bx--modal-close__icon" width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"><path d="M12 4.7L11.3 4 8 7.3 4.7 4 4 4.7 7.3 8 4 11.3 4.7 12 8 8.7 11.3 12 12 11.3 8.7 8z"></path></svg>
</button>
</div>
<div class="bx--row">
<div class="bx--col bx--col--auto bx--form-item">
<input class="bx--toggle-input bx--toggle-input--small" id="metric" type="checkbox" name="metric" checked="checked">
<label class="bx--toggle-input__label" for="metric"
aria-label="example toggle with state indicator text">
<span class="bx--toggle__switch">
<svg class="bx--toggle__check" width="6px" height="5px" viewBox="0 0 6 5">
<path d="M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z" />
</svg>
<span class="bx--toggle__text--on" aria-hidden="true">Show in Celsius</span>
<span class="bx--toggle__text--off" aria-hidden="true">Show in Fahrenheit</span>
</span>
</label>
<!-- Note: Modals with content that scrolls, at any viewport, requires `tabindex="0"` on the `bx--modal-content` element -->
<div class="bx--modal-content bx--modal-content--with-form" >
<div class="bx--form-item">
<label for="e-tname" class="bx--label">Printer Name</label>
<input id="e-tname" type="text" class="bx--text-input" placeholder="Custom name" data-modal-primary-focus maxlength="20">
</div>
</div>
<div class="bx--row">
<div class="bx--form-item bx--col bx--col--auto">
<label for="openWeatherMapApiKey" class="bx--label">OpenWeatherMap API Key (get from <a href="https://openweathermap.org/" target="_BLANK">here</a>)</label>
<input id="openWeatherMapApiKey" type="text"
class="bx--text-input"
name="openWeatherMapApiKey"
value="e6df83d1aa3df77420f265a2e263a5d3"
maxlength="60">
</div>
</div>
<div class="bx--row">
<div class="bx--form-item bx--col bx--col--auto">
<label for="city1" class="bx--label">Zeuthen (<a href="http://openweathermap.org/find" target="_BLANK"><i class="fa fa-search"></i> Search for City ID</a>)</label>
<input id="city1" type="text"
class="bx--text-input"
name="city1"
value="2804646"
onkeypress="return isNumberKey(event)">
</div>
</div>
<div class="bx--row">
<div class="bx--form-item bx--col bx--col--auto bx--select">
<label for="language" class="bx--label">Weather Language</label>
<div class="bx--form-item bx--select">
<label for="e-tapi" class="bx--label">API Type</label>
<div class="bx--select-input__wrapper">
<select id="language" class="bx--select-input" name="language">
<option class="bx--select-option">ar</option>
<option class="bx--select-option">bg</option>
<option class="bx--select-option">ca</option>
<option class="bx--select-option">cz</option>
<option class="bx--select-option" selected="">de</option>
<option class="bx--select-option">el</option>
<option class="bx--select-option">en</option>
<option class="bx--select-option">fa</option>
<option class="bx--select-option">fi</option>
<option class="bx--select-option">fr</option>
<option class="bx--select-option">gl</option>
<option class="bx--select-option">hr</option>
<option class="bx--select-option">hu</option>
<option class="bx--select-option">it</option>
<option class="bx--select-option">ja</option>
<option class="bx--select-option">kr</option>
<option class="bx--select-option">la</option>
<option class="bx--select-option">lt</option>
<option class="bx--select-option">mk</option>
<option class="bx--select-option">nl</option>
<option class="bx--select-option">pl</option>
<option class="bx--select-option">pt</option>
<option class="bx--select-option">ro</option>
<option class="bx--select-option">ru</option>
<option class="bx--select-option">se</option>
<option class="bx--select-option">sk</option>
<option class="bx--select-option">sl</option>
<option class="bx--select-option">es</option>
<option class="bx--select-option">tr</option>
<option class="bx--select-option">ua</option>
<option class="bx--select-option">vi</option>
<option class="bx--select-option">zh_cn</option>
<option class="bx--select-option">zh_tw</option>
<select id="e-tapi" class="bx--select-input" name="e-tapi">
<option class="bx--select-option">Duet</option>
<option class="bx--select-option">Klipper</option>
<option class="bx--select-option" selected>Octoprint</option>
<option class="bx--select-option">Repetier</option>
</select>
<svg focusable="false" preserveAspectRatio="xMidYMid meet" style="will-change: transform;" xmlns="http://www.w3.org/2000/svg" class="bx--select__arrow" width="10" height="6" viewBox="0 0 10 6" aria-hidden="true"><path d="M5 6L0 1 0.7 0.3 5 4.6 9.3 0.3 10 1z"></path></svg>
</div>
</div>
</div>
<div class="bx--row">
<div class="bx--form-item bx--col bx--col--auto">
<button class="bx--btn bx--btn--primary" type="submit">Save</button>
<div class="bx--form-item">
<label for="e-taddr" class="bx--label">Hostname or IP Address (do not include http://)</label>
<input id="e-taddr" name="e-taddr" type="text" class="bx--text-input" placeholder="Target Address" maxlength="60">
</div>
<div class="bx--form-item">
<label for="e-tport" class="bx--label">Port</label>
<input id="e-tport" name="e-tport" type="text" class="bx--text-input" placeholder="Target port" maxlength="5" value="80">
</div>
<div class="bx--form-item">
<input class="bx--toggle-input bx--toggle-input--small" id="e-tpsu" type="checkbox" name="e-tpsu">
<label class="bx--toggle-input__label" for="e-tpsu">
<span class="bx--toggle__switch">
<svg class="bx--toggle__check" width="6px" height="5px" viewBox="0 0 6 5">
<path d="M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z" />
</svg>
<span class="bx--toggle__text--off" aria-hidden="true">PSU control deactivated</span>
<span class="bx--toggle__text--on" aria-hidden="true">PSU control activated</span>
</span>
</label>
</div>
<div class="bx--form-item">
<input class="bx--toggle-input bx--toggle-input--small" id="e-tapipw" type="checkbox" name="e-tapipw" onchange="showhide(this, 'apac')" checked="checked">
<label class="bx--toggle-input__label" for="e-tapipw">
<span class="bx--toggle__switch">
<svg class="bx--toggle__check" width="6px" height="5px" viewBox="0 0 6 5">
<path d="M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z" />
</svg>
<span class="bx--toggle__text--off" aria-hidden="true">Haproxy or basic auth deactivated</span>
<span class="bx--toggle__text--on" aria-hidden="true">Haproxy or basic auth activated</span>
</span>
</label>
</div>
<div class="bx--form-item" data-sh="apac">
<label for="e-tapiuser" class="bx--label">User ID (for this interface)</label>
<input id="e-tapiuser" type="text"
class="bx--text-input"
name="e-tapiuser"
value="admin"
maxlength="30">
</div>
<div class="bx--form-item" data-sh="apac">
<label for="e-tapipass" class="bx--label">Password (for this interface)</label>
<input id="e-tapipass" type="password"
class="bx--text-input"
name="e-tapipass"
value="admin">
</div><br><br>
</div>
</form>
<script>function isNumberKey(e){var h=e.which?e.which:event.keyCode;return!(h>31&&(h<48||h>57))}</script>
<br><br><br>
<div class="bx--modal-content--overflow-indicator"></div>
<div class="bx--modal-footer">
<button class="bx--btn bx--btn--secondary" type="button" onclick="closeModal('modal-pyu0ribosn')">Abort</button>
<button class="bx--btn bx--btn--primary" type="button">Save</button>
</div>
</div>
<!-- Note: focusable span allows for focus wrap feature within Modals -->
<span tabindex="0"></span>
</div>
</div>
<div data-modal id="modal-ed454ftfa4q" class="bx--modal bx--modal--danger" role="dialog"
aria-modal="true" aria-labelledby="modal-ed454ftfa4q-label" aria-describedby="modal-ed454ftfa4q-heading" tabindex="-1">
<div class="bx--modal-container">
<form method="GET" >
<div class="bx--modal-header">
<p class="bx--modal-header__label bx--type-delta" id="modal-ed454ftfa4q-label">Warning!</p>
<p class="bx--modal-header__heading bx--type-beta" id="modal-ed454ftfa4q-heading">Delete configuration for I3 Mega</p>
<button class="bx--modal-close" type="button" data-modal-close aria-label="close modal" onclick="closeModal('modal-ed454ftfa4q')" >
<svg focusable="false" preserveAspectRatio="xMidYMid meet" style="will-change: transform;" xmlns="http://www.w3.org/2000/svg" class="bx--modal-close__icon" width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"><path d="M12 4.7L11.3 4 8 7.3 4.7 4 4 4.7 7.3 8 4 11.3 4.7 12 8 8.7 11.3 12 12 11.3 8.7 8z"></path></svg>
</button>
</div>
<!-- Note: Modals with content that scrolls, at any viewport, requires `tabindex="0"` on the `bx--modal-content` element -->
<div class="bx--modal-content" >
<p> you really want to delete the configured printer?</p><br><br>
</div>
<div class="bx--modal-content--overflow-indicator"></div>
<div class="bx--modal-footer">
<button class="bx--btn bx--btn--secondary" type="reset" onclick="closeModal('modal-ed454ftfa4q')">Abort</button>
<button class="bx--btn bx--btn--danger" type="submit" aria-label="Danger"
data-modal-primary-focus>Delete</button>
</div>
</form>
</div>
<!-- Note: focusable span allows for focus wrap feature within Modals -->
<span tabindex="0"></span>
</div>
<div class='bx--loading-overlay hidden' id='pageloading'>
<div data-loading class='bx--loading'>
<svg class='bx--loading__svg' viewBox='-75 -75 150 150'>
<title>Loading</title>
<circle class='bx--loading__stroke' cx='0' cy='0' r='37.5' />
</svg>
</div>
</div>
<form>
<button type="submit">Test</button>
</form>
<script src="https://unpkg.com/carbon-components/scripts/carbon-components.min.js"></script>
@ -249,6 +363,25 @@
document.getElementById('sidebar').classList.remove('bx--header-panel--expanded');
document.getElementById('wifiinfo').classList.toggle('hidden');
}
function showhide(a,b) {
var e = $("[data-sh='"+b+"']");
console.log();
if (a.checked||a.prop('checked')) {
e.removeClass('hidden');
} else {
e.addClass('hidden');
}
}
function xtest(){
$('#pageloading').removeClass('hidden');
}
$(function() {
$('form').on("submit", function(e){$('#pageloading').removeClass('hidden'); e.preventDefault(); return false;})
});
showhide($('#e-tapipw'), 'apac');
</script>
</body>

25
include/MemoryHelper.h Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include <Arduino.h>
class MemoryHelper {
public:
/**
* @brief Clean copy string to char[]
*
* @param src Source string to copy
* @param dest Destination char array
* @param destSize Destination array size
* @return size_t Num bytes copied
*/
static size_t stringToChar(String src, char *dest, size_t destSize) {
memset(dest, 0, destSize);
if (src.length() <= 0) {
return 0;
}
if (src.length() < destSize) {
destSize = src.length();
}
memcpy(dest, src.c_str(), destSize);
return destSize;
}
};

View File

@ -5,36 +5,42 @@
#include "Debug.h"
#include "../Network/JsonRequestClient.h"
#include "PrinterDataStruct.h"
#include "../../include/MemoryHelper.h"
/**
* @brief Basic function definitions for an printer client like an interface
*/
class BasePrinterClient {
public:
virtual void getPrinterJobResults();
virtual void getPrinterPsuState();
virtual void updatePrintClient();
virtual void getPrinterJobResults(PrinterDataStruct *printerData) = 0;
virtual void getPrinterPsuState(PrinterDataStruct *printerData) = 0;
virtual void updatePrintClient(PrinterDataStruct *printerData) = 0;
virtual String getClientType() = 0;
virtual boolean isValidConfig(PrinterDataStruct *printerData) = 0;
virtual String getAveragePrintTime() = 0;
virtual String getEstimatedPrintTime() = 0;
virtual String getFileName() = 0;
virtual String getFileSize() = 0;
virtual String getLastPrintTime() = 0;
virtual String getProgressCompletion() = 0;
virtual String getProgressFilepos() = 0;
virtual String getProgressPrintTime() = 0;
virtual String getProgressPrintTimeLeft() = 0;
virtual int getState() = 0;
virtual String getStateAsText() = 0;
virtual boolean isPrinting() = 0;
virtual boolean isOperational() = 0;
virtual boolean isPSUoff() = 0;
virtual String getTempBedActual() = 0;
virtual String getTempBedTarget() = 0;
virtual String getTempToolActual() = 0;
virtual String getTempToolTarget() = 0;
virtual String getFilamentLength() = 0;
virtual String getValueRounded(String value) = 0;
virtual String getError() = 0;
virtual String getPrinterType() = 0;
virtual int getPrinterPort() = 0;
virtual String getPrinterName() = 0;
virtual void setPrinterName(String printer) = 0;
/**
* @brief Reset all dynamic variables for printer
* @param printerData Handle to printer struct
*/
static void resetPrinterData(PrinterDataStruct *printerData) {
printerData->state = PRINTER_STATE_OFFLINE;
printerData->isPrinting = false;
printerData->isPSUoff = false;
printerData->averagePrintTime = 0;
printerData->bedTargetTemp = 0.0f;
printerData->bedTemp = 0.0f;
MemoryHelper::stringToChar("", printerData->error, 120);
MemoryHelper::stringToChar("", printerData->encAuth, 120);
printerData->estimatedPrintTime = 0;
printerData->filamentLength = 0.0f;
MemoryHelper::stringToChar("", printerData->fileName, 60);
printerData->fileSize = 0;
printerData->lastPrintTime = 0;
MemoryHelper::stringToChar("", printerData->progressCompletion, 60);
printerData->progressFilepos = 0;
printerData->progressPrintTime = 0;
printerData->progressPrintTimeLeft = 0;
printerData->toolTargetTemp = 0.0f;
printerData->toolTemp = 0.0f;
}
};

View File

@ -1,171 +1,73 @@
#include "BasePrinterClientImpl.h"
/**
* @brief Construct a new Base Printer Client Impl:: Base Printer Client Impl object
*
* @param clientType Client type name
* @param globalDataController Handle to global data controller
* @param debugController Handle to debug controller
* @param jsonRequestClient Handle to json request instance
*/
BasePrinterClientImpl::BasePrinterClientImpl(
String printerType,
String clientType,
GlobalDataController *globalDataController,
DebugController *debugController,
JsonRequestClient *jsonRequestClient
) {
this->globalDataController = globalDataController;
this->debugController = debugController;
this->printerType = printerType;
this->clientType = clientType;
this->jsonRequestClient = jsonRequestClient;
}
// Reset all PrinterData
void BasePrinterClientImpl::resetPrintData() {
this->printerData.averagePrintTime = "";
this->printerData.estimatedPrintTime = "";
this->printerData.fileName = "";
this->printerData.fileSize = "";
this->printerData.lastPrintTime = "";
this->printerData.progressCompletion = "";
this->printerData.progressFilepos = "";
this->printerData.progressPrintTime = "";
this->printerData.progressPrintTimeLeft = "";
this->printerData.state = PRINTER_STATE_OFFLINE;
this->printerData.toolTemp = "";
this->printerData.toolTargetTemp = "";
this->printerData.filamentLength = "";
this->printerData.bedTemp = "";
this->printerData.bedTargetTemp = "";
this->printerData.isPrinting = false;
this->printerData.isPSUoff = false;
this->printerData.error = "";
/**
* @brief Get the type of client for this instance
* @return String
*/
String BasePrinterClientImpl::getClientType() {
return this->clientType;
}
String BasePrinterClientImpl::getAveragePrintTime(){
return printerData.averagePrintTime;
/**
* @brief Update data for client, like AUTH
* @param printerData Handle to printer struct
*/
void BasePrinterClientImpl::updatePrintClient(PrinterDataStruct *printerData) {
if (printerData->basicAuthNeeded) {
String encodedAuth = "";
String userpass = String(printerData->basicAuthUsername) + ":" + String(printerData->basicAuthPassword);
base64 b64;
MemoryHelper::stringToChar(b64.encode(userpass, true), printerData->encAuth, 120);
}
}
String BasePrinterClientImpl::getEstimatedPrintTime() {
return printerData.estimatedPrintTime;
}
String BasePrinterClientImpl::getFileName() {
return printerData.fileName;
}
String BasePrinterClientImpl::getFileSize() {
return printerData.fileSize;
}
String BasePrinterClientImpl::getLastPrintTime(){
return printerData.lastPrintTime;
}
String BasePrinterClientImpl::getProgressCompletion() {
return String(printerData.progressCompletion.toInt());
}
String BasePrinterClientImpl::getProgressFilepos() {
return printerData.progressFilepos;
}
String BasePrinterClientImpl::getProgressPrintTime() {
return printerData.progressPrintTime;
}
String BasePrinterClientImpl::getProgressPrintTimeLeft() {
String rtnValue = printerData.progressPrintTimeLeft;
if (getProgressCompletion() == "100") {
rtnValue = "0"; // Print is done so this should be 0 this is a fix for Duet
/**
* @brief Validate configuration for printer
* @param printerData Handle to printer struct
* @return boolean
*/
boolean BasePrinterClientImpl::isValidConfig(PrinterDataStruct *printerData) {
boolean rtnValue = true;
if ((String(printerData->remoteAddress) == "") || (String(printerData->remotePort) == "")) {
MemoryHelper::stringToChar("Server address or host name is required", printerData->error, 120);
rtnValue = false;
}
if (String(printerData->error) != "") {
printerData->state = PRINTER_STATE_ERROR;
rtnValue = false;
}
return rtnValue;
}
int BasePrinterClientImpl::getState() {
return printerData.state;
}
String BasePrinterClientImpl::getStateAsText() {
switch (this->getState())
{
case PRINTER_STATE_ERROR:
return "Error";
case PRINTER_STATE_STANDBY:
return "Standby";
case PRINTER_STATE_PRINTING:
return "Printing";
case PRINTER_STATE_PAUSED:
return "Paused";
case PRINTER_STATE_COMPLETED:
return "Completed";
default:
return "Offline";
}
}
boolean BasePrinterClientImpl::isPrinting() {
return printerData.isPrinting;
}
boolean BasePrinterClientImpl::isPSUoff() {
return printerData.isPSUoff;
}
boolean BasePrinterClientImpl::isOperational() {
/**
* @brief Check if printer is pperational
* @param printerData Handle to printer struct
* @return boolean
*/
boolean BasePrinterClientImpl::isOperational(PrinterDataStruct *printerData) {
boolean operational = false;
if ((printerData.state != PRINTER_STATE_OFFLINE) || isPrinting()) {
if ((printerData->state != PRINTER_STATE_OFFLINE) || printerData->isPrinting) {
operational = true;
}
return operational;
}
String BasePrinterClientImpl::getTempBedActual() {
return printerData.bedTemp;
}
String BasePrinterClientImpl::getTempBedTarget() {
return printerData.bedTargetTemp;
}
String BasePrinterClientImpl::getTempToolActual() {
return printerData.toolTemp;
}
String BasePrinterClientImpl::getTempToolTarget() {
return printerData.toolTargetTemp;
}
String BasePrinterClientImpl::getFilamentLength() {
return printerData.filamentLength;
}
String BasePrinterClientImpl::getError() {
return printerData.error;
}
String BasePrinterClientImpl::getValueRounded(String value) {
float f = value.toFloat();
int rounded = (int)(f+0.5f);
return String(rounded);
}
String BasePrinterClientImpl::getPrinterType() {
return this->printerType;
}
int BasePrinterClientImpl::getPrinterPort() {
return this->globalDataController->getPrinterPort();
}
String BasePrinterClientImpl::getPrinterName() {
return printerData.printerName;
}
void BasePrinterClientImpl::setPrinterName(String printer) {
printerData.printerName = printer;
}
String BasePrinterClientImpl::getInstanceServerTarget() {
String targetServer = this->globalDataController->getPrinterServer();
if (this->globalDataController->getPrinterServer() == "") {
targetServer = this->globalDataController->getPrinterHostName();
}
return targetServer;
}
int BasePrinterClientImpl::getInstanceServerPort() {
return this->globalDataController->getPrinterPort();
}

View File

@ -2,54 +2,22 @@
#include "BasePrinterClient.h"
#include "../Global/GlobalDataController.h"
/**
* @brief Basic implementations for an printer client with needed data
*/
class BasePrinterClientImpl : public BasePrinterClient {
protected:
GlobalDataController *globalDataController;
DebugController *debugController;
JsonRequestClient *jsonRequestClient;
String printerType = "Octoprint";
PrinterDataStruct printerData;
String result;
String encodedAuth = "";
String clientType = "Octoprint";
public:
BasePrinterClientImpl(String printerType, GlobalDataController *globalDataController, DebugController *debugController, JsonRequestClient *jsonRequestClient);
void getPrinterJobResults() {};
void getPrinterPsuState() {};
void updatePrintClient() {};
void resetPrintData();
String getAveragePrintTime();
String getEstimatedPrintTime();
String getFileName();
String getFileSize();
String getLastPrintTime();
String getProgressCompletion();
String getProgressFilepos();
String getProgressPrintTime();
String getProgressPrintTimeLeft();
int getState();
String getStateAsText();
boolean isPrinting();
boolean isOperational();
boolean isPSUoff();
String getTempBedActual();
String getTempBedTarget();
String getTempToolActual();
String getTempToolTarget();
String getFilamentLength();
String getValueRounded(String value);
String getError();
String getPrinterType();
int getPrinterPort();
String getPrinterName();
void setPrinterName(String printer);
protected:
String getInstanceServerTarget();
int getInstanceServerPort();
BasePrinterClientImpl(String clientType, GlobalDataController *globalDataController, DebugController *debugController, JsonRequestClient *jsonRequestClient);
void getPrinterJobResults(PrinterDataStruct *printerData) {};
void getPrinterPsuState(PrinterDataStruct *printerData) {};
void updatePrintClient(PrinterDataStruct *printerData);
String getClientType();
boolean isOperational(PrinterDataStruct *printerData);
boolean isValidConfig(PrinterDataStruct *printerData);
};

View File

@ -1,9 +0,0 @@
#pragma once
/**
* Clients
*/
#define DUET_CLIENT 1
#define KLIPPER_CLIENT 2
#define REPETIER_CLIENT 3
#define OCTOPRINT_CLIENT 4

View File

@ -3,48 +3,35 @@
#include "DuetClient.h"
/**
* @brief Construct a new Duet Client:: Duet Client object
*
* @param globalDataController Handle to global data controller
* @param debugController Handle to debug controller
* @param jsonRequestClient Handle to json request instance
*/
DuetClient::DuetClient(GlobalDataController *globalDataController, DebugController *debugController, JsonRequestClient *jsonRequestClient)
: BasePrinterClientImpl("Duet", globalDataController, debugController, jsonRequestClient) {
this->updatePrintClient();
: BasePrinterClientImpl("Duet", globalDataController, debugController, jsonRequestClient) {
}
void DuetClient::updatePrintClient() {
encodedAuth = "";
if (this->globalDataController->getPrinterAuthUser() != "") {
String userpass = this->globalDataController->getPrinterAuthUser() + ":" + this->globalDataController->getPrinterAuthPass();
base64 b64;
encodedAuth = b64.encode(userpass, true);
}
pollPsu = this->globalDataController->hasPrinterPsu();
}
boolean DuetClient::validate() {
boolean rtnValue = false;
printerData.error = "";
if ((this->globalDataController->getPrinterServer() == "") && (this->globalDataController->getPrinterHostName() == "")) {
printerData.error += "Server address or host name is required; ";
}
if (printerData.error == "") {
rtnValue = true;
}
return rtnValue;
}
void DuetClient::getPrinterJobResults() {
// const size_t bufferSize = JSON_ARRAY_SIZE(4) + JSON_OBJECT_SIZE(1) + 4*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(7) + JSON_OBJECT_SIZE(9) + 426;
/**
* @brief Refresh job and state data for printer
* @param printerData Handle to printer struct
*/
void DuetClient::getPrinterJobResults(PrinterDataStruct *printerData) {
const size_t bufferSize = 2048; // according to ArduinoJson assistant
DynamicJsonDocument *jsonDoc;
if (!validate()) {
if (!this->isValidConfig(printerData)) {
return;
}
// Req 1
this->debugController->printLn("Get Duet Data: " + this->getInstanceServerTarget() + ":" + String(this->getInstanceServerPort()));
this->debugController->printLn("Get Duet Data: " + String(printerData->remoteAddress) + ":" + String(printerData->remotePort));
jsonDoc = this->jsonRequestClient->requestJson(
PRINTER_REQUEST_GET,
this->getInstanceServerTarget(),
this->getInstanceServerPort(),
this->encodedAuth,
String(printerData->remoteAddress),
printerData->remotePort,
String(printerData->encAuth),
"/rr_status?type=1",
"",
bufferSize,
@ -52,29 +39,27 @@ void DuetClient::getPrinterJobResults() {
);
if (this->jsonRequestClient->getLastError() != "") {
this->debugController->printLn(this->jsonRequestClient->getLastError());
printerData.error = this->jsonRequestClient->getLastError();
printerData.state = PRINTER_STATE_OFFLINE;
printerData.isPrinting = false;
printerData.toolTemp = "";
printerData.toolTargetTemp = "";
printerData.bedTemp = "";
printerData.bedTargetTemp = "";
BasePrinterClient::resetPrinterData(printerData);
if (this->jsonRequestClient->getLastError().indexOf("PARSER") == 0) {
MemoryHelper::stringToChar(this->jsonRequestClient->getLastError(), printerData->error, 120);
printerData->state = PRINTER_STATE_ERROR;
}
return;
}
printerData.state = this->translateState((const char*)(*jsonDoc)["status"]);
printerData->state = DuetClient::translateState((const char*)(*jsonDoc)["status"]);
if (BasePrinterClientImpl::isOperational()) {
this->debugController->printLn("Status: " + this->getStateAsText());
if (this->isOperational(printerData)) {
this->debugController->printLn("Status: " + this->globalDataController->getPrinterStateAsText(printerData));
} else {
this->debugController->printLn("Printer Not Operational");
}
if (printerData.state == PRINTER_STATE_PRINTING) {
printerData.isPrinting = true;
if (printerData->state == PRINTER_STATE_PRINTING) {
printerData->isPrinting = true;
} else {
// We dont printing, so abort function here
printerData.isPrinting = false;
printerData->isPrinting = false;
return;
}
@ -82,9 +67,9 @@ void DuetClient::getPrinterJobResults() {
// Req 2
jsonDoc = this->jsonRequestClient->requestJson(
PRINTER_REQUEST_GET,
this->getInstanceServerTarget(),
this->getInstanceServerPort(),
this->encodedAuth,
String(printerData->remoteAddress),
printerData->remotePort,
String(printerData->encAuth),
"/rr_status?type=3",
"",
bufferSize,
@ -92,76 +77,48 @@ void DuetClient::getPrinterJobResults() {
);
if (this->jsonRequestClient->getLastError() != "") {
this->debugController->printLn(this->jsonRequestClient->getLastError());
printerData.error = this->jsonRequestClient->getLastError();
printerData.state = PRINTER_STATE_OFFLINE;
printerData.isPrinting = false;
printerData.toolTemp = "";
printerData.toolTargetTemp = "";
printerData.bedTemp = "";
printerData.bedTargetTemp = "";
BasePrinterClient::resetPrinterData(printerData);
if (this->jsonRequestClient->getLastError().indexOf("PARSER") == 0) {
MemoryHelper::stringToChar(this->jsonRequestClient->getLastError(), printerData->error, 120);
printerData->state = PRINTER_STATE_ERROR;
}
return;
}
printerData.filamentLength = (const char*)(*jsonDoc)["result"]["status"]["job"]["print_stats"]["filament_used"];
printerData.progressPrintTime = (const char*)(*jsonDoc)["printDuration"];
printerData.fileName = (const char*)(*jsonDoc)["result"]["status"]["print_stats"]["filename"];
printerData.progressCompletion = (int)(*jsonDoc)["fractionPrinted"];
printerData.toolTemp = (int)(*jsonDoc)["temps"]["current"][1];
printerData.toolTargetTemp = (int)(*jsonDoc)["temps"]["tools"]["active"][0][0];
printerData.bedTemp = (int)(*jsonDoc)["temps"]["bed"]["current"];
printerData.bedTargetTemp = (int)(*jsonDoc)["temps"]["bed"]["active"];
//printerData.filamentLength = (const char*)(*jsonDoc)["result"]["status"]["job"]["print_stats"]["filament_used"];
//printerData.progressPrintTime = (const char*)(*jsonDoc)["printDuration"];
//printerData.fileName = (const char*)(*jsonDoc)["result"]["status"]["print_stats"]["filename"];
//printerData.progressCompletion = (int)(*jsonDoc)["fractionPrinted"];
printerData->toolTemp = (int)(*jsonDoc)["temps"]["current"][1];
printerData->toolTargetTemp = (int)(*jsonDoc)["temps"]["tools"]["active"][0][0];
printerData->bedTemp = (int)(*jsonDoc)["temps"]["bed"]["current"];
printerData->bedTargetTemp = (int)(*jsonDoc)["temps"]["bed"]["active"];
float fileProgress = (float)(*jsonDoc)["fractionPrinted"];
printerData.progressFilepos = (const char*)(*jsonDoc)["filePosition"];
printerData.estimatedPrintTime = (float)(*jsonDoc)["file"];
//printerData.progressFilepos = (const char*)(*jsonDoc)["filePosition"];
printerData->estimatedPrintTime = (float)(*jsonDoc)["file"];
/*
printerData.progressPrintTimeLeft : No metadata is available, print duration and progress can be used to calculate the ETA:
*/
float totalPrintTime = printerData.progressPrintTime.toFloat() / fileProgress;
printerData.progressPrintTimeLeft = String(totalPrintTime - printerData.progressPrintTime.toFloat());
//float totalPrintTime = printerData.progressPrintTime.toFloat() / fileProgress;
//printerData.progressPrintTimeLeft = String(totalPrintTime - printerData.progressPrintTime.toFloat());
if (BasePrinterClientImpl::isOperational()) {
this->debugController->printLn("Status: " + this->getStateAsText() + " " + printerData.fileName + "(" + printerData.progressCompletion + "%)");
if (this->isOperational(printerData)) {
this->debugController->printLn("Status: "
+ this->globalDataController->getPrinterStateAsText(printerData) + " "
+ String(printerData->fileName) + "("
+ String(printerData->progressCompletion) + "%)"
);
}
}
void DuetClient::getPrinterPsuState() {
/*// get the PSU state (if enabled and printer operational)
if (pollPsu && BasePrinterClientImpl::isOperational()) {
if (!validate()) {
printerData.isPSUoff = false; // we do not know PSU state, so assume on.
return;
}
String apiPostData = "POST /api/plugin/psucontrol HTTP/1.1";
String apiPostBody = "{\"command\":\"getPSUState\"}";
WiFiClient printClient = getPostRequest(apiPostData,apiPostBody);
if (printerData.error != "") {
printerData.isPSUoff = false; // we do not know PSU state, so assume on.
return;
}
const size_t bufferSize3 = JSON_OBJECT_SIZE(2) + 300;
DynamicJsonDocument jsonBuffer(bufferSize3);
// Parse JSON object
DeserializationError error = deserializeJson(jsonBuffer, printClient);
if (error) {
printerData.isPSUoff = false; // we do not know PSU state, so assume on
return;
}
String psu = (const char*)jsonBuffer["isPSUOn"];
if (psu == "true") {
printerData.isPSUoff = false; // PSU checked and is on
} else {
printerData.isPSUoff = true; // PSU checked and is off, set flag
}
printClient.stop(); //stop client
} else {
printerData.isPSUoff = false; // we are not checking PSU state, so assume on
} */
/**
* @brief Refresh psu state data for printer
* @param printerData Handle to printer struct
*/
void DuetClient::getPrinterPsuState(PrinterDataStruct *printerData) {
}
/**
* We translate the avail states
* - C (configuration file is being processed)

View File

@ -6,18 +6,15 @@
#include "BasePrinterClientImpl.h"
#include "../Global/GlobalDataController.h"
/**
* @brief DUET Client implementation
*/
class DuetClient : public BasePrinterClientImpl {
private:
boolean pollPsu;
boolean validate();
public:
DuetClient(GlobalDataController *globalDataController, DebugController *debugController, JsonRequestClient *jsonRequestClient);
void getPrinterJobResults(PrinterDataStruct *printerData) override;
void getPrinterPsuState(PrinterDataStruct *printerData) override;
void getPrinterJobResults() override;
void getPrinterPsuState() override;
void updatePrintClient() override;
int translateState(String stateText);
private:
static int translateState(String stateText);
};

View File

@ -3,48 +3,35 @@
#include "KlipperClient.h"
/**
* @brief Construct a new Klipper Client:: Klipper Client object
*
* @param globalDataController Handle to global data controller
* @param debugController Handle to debug controller
* @param jsonRequestClient Handle to json request instance
*/
KlipperClient::KlipperClient(GlobalDataController *globalDataController, DebugController *debugController, JsonRequestClient *jsonRequestClient)
: BasePrinterClientImpl("Klipper", globalDataController, debugController, jsonRequestClient) {
this->updatePrintClient();
}
void KlipperClient::updatePrintClient() {
encodedAuth = "";
if (this->globalDataController->getPrinterAuthUser() != "") {
String userpass = this->globalDataController->getPrinterAuthUser() + ":" + this->globalDataController->getPrinterAuthPass();
base64 b64;
encodedAuth = b64.encode(userpass, true);
}
pollPsu = this->globalDataController->hasPrinterPsu();
}
boolean KlipperClient::validate() {
boolean rtnValue = false;
printerData.error = "";
if ((this->globalDataController->getPrinterServer() == "") && (this->globalDataController->getPrinterHostName() == "")) {
printerData.error += "Server address or host name is required; ";
}
if (printerData.error == "") {
rtnValue = true;
}
return rtnValue;
}
void KlipperClient::getPrinterJobResults() {
// const size_t bufferSize = JSON_ARRAY_SIZE(4) + JSON_OBJECT_SIZE(1) + 4*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(7) + JSON_OBJECT_SIZE(9) + 426;
/**
* @brief Refresh job and state data for printer
* @param printerData Handle to printer struct
*/
void KlipperClient::getPrinterJobResults(PrinterDataStruct *printerData) {
const size_t bufferSize = 1536; // according to ArduinoJson assistant
DynamicJsonDocument *jsonDoc;
if (!validate()) {
if (!this->isValidConfig(printerData)) {
return;
}
// Req 1
this->debugController->printLn("Get Klipper Data: " + this->getInstanceServerTarget() + ":" + String(this->getInstanceServerPort()));
this->debugController->printLn("Get Klipper Data: " + String(printerData->remoteAddress) + ":" + String(printerData->remotePort));
jsonDoc = this->jsonRequestClient->requestJson(
PRINTER_REQUEST_GET,
this->getInstanceServerTarget(),
this->getInstanceServerPort(),
this->encodedAuth,
String(printerData->remoteAddress),
printerData->remotePort,
String(printerData->encAuth),
"/printer/objects/query?print_stats",
"",
bufferSize,
@ -52,41 +39,39 @@ void KlipperClient::getPrinterJobResults() {
);
if (this->jsonRequestClient->getLastError() != "") {
this->debugController->printLn(this->jsonRequestClient->getLastError());
printerData.error = this->jsonRequestClient->getLastError();
printerData.state = PRINTER_STATE_OFFLINE;
printerData.isPrinting = false;
printerData.toolTemp = "";
printerData.toolTargetTemp = "";
printerData.bedTemp = "";
printerData.bedTargetTemp = "";
BasePrinterClient::resetPrinterData(printerData);
if (this->jsonRequestClient->getLastError().indexOf("PARSER") == 0) {
MemoryHelper::stringToChar(this->jsonRequestClient->getLastError(), printerData->error, 120);
printerData->state = PRINTER_STATE_ERROR;
}
return;
}
printerData.state = this->translateState((const char*)(*jsonDoc)["result"]["status"]["print_stats"]["state"]);
printerData.filamentLength = (const char*)(*jsonDoc)["result"]["status"]["job"]["print_stats"]["filament_used"];
printerData.progressPrintTime = (const char*)(*jsonDoc)["result"]["status"]["print_stats"]["print_duration"];
printerData.fileName = (const char*)(*jsonDoc)["result"]["status"]["print_stats"]["filename"];
printerData->state = KlipperClient::translateState((const char*)(*jsonDoc)["result"]["status"]["print_stats"]["state"]);
//printerData.filamentLength = (const char*)(*jsonDoc)["result"]["status"]["job"]["print_stats"]["filament_used"];
//printerData.progressPrintTime = (const char*)(*jsonDoc)["result"]["status"]["print_stats"]["print_duration"];
//printerData.fileName = (const char*)(*jsonDoc)["result"]["status"]["print_stats"]["filename"];
if (BasePrinterClientImpl::isOperational()) {
this->debugController->printLn("Status: " + this->getStateAsText());
if (this->isOperational(printerData)) {
this->debugController->printLn("Status: " + this->globalDataController->getPrinterStateAsText(printerData));
} else {
this->debugController->printLn("Printer Not Operational");
}
if (printerData.state == PRINTER_STATE_PRINTING) {
printerData.isPrinting = true;
if (printerData->state == PRINTER_STATE_PRINTING) {
printerData->isPrinting = true;
} else {
// We dont printing, so abort function here
printerData.isPrinting = false;
printerData->isPrinting = false;
return;
}
// Req 2
jsonDoc = this->jsonRequestClient->requestJson(
PRINTER_REQUEST_GET,
this->getInstanceServerTarget(),
this->getInstanceServerPort(),
this->encodedAuth,
String(printerData->remoteAddress),
printerData->remotePort,
String(printerData->encAuth),
"/printer/objects/query?heater_bed&extruder&display_status&toolhead&virtual_sdcard",
"",
bufferSize,
@ -94,70 +79,43 @@ void KlipperClient::getPrinterJobResults() {
);
if (this->jsonRequestClient->getLastError() != "") {
this->debugController->printLn(this->jsonRequestClient->getLastError());
printerData.error = this->jsonRequestClient->getLastError();
printerData.state = PRINTER_STATE_OFFLINE;
printerData.isPrinting = false;
printerData.toolTemp = "";
printerData.toolTargetTemp = "";
printerData.bedTemp = "";
printerData.bedTargetTemp = "";
BasePrinterClient::resetPrinterData(printerData);
if (this->jsonRequestClient->getLastError().indexOf("PARSER") == 0) {
MemoryHelper::stringToChar(this->jsonRequestClient->getLastError(), printerData->error, 120);
printerData->state = PRINTER_STATE_ERROR;
}
return;
}
printerData.progressCompletion = (int)(*jsonDoc)["result"]["status"]["display_status"]["progress"];
printerData.toolTemp = (int)(*jsonDoc)["result"]["status"]["extruder"]["temperature"];
printerData.toolTargetTemp = (int)(*jsonDoc)["result"]["status"]["extruder"]["target"];
printerData.bedTemp = (int)(*jsonDoc)["result"]["status"]["heater_bed"]["temperature"];
printerData.bedTargetTemp = (int)(*jsonDoc)["result"]["status"]["heater_bed"]["target"];
//printerData.progressCompletion = (int)(*jsonDoc)["result"]["status"]["display_status"]["progress"];
printerData->toolTemp = (int)(*jsonDoc)["result"]["status"]["extruder"]["temperature"];
printerData->toolTargetTemp = (int)(*jsonDoc)["result"]["status"]["extruder"]["target"];
printerData->bedTemp = (int)(*jsonDoc)["result"]["status"]["heater_bed"]["temperature"];
printerData->bedTargetTemp = (int)(*jsonDoc)["result"]["status"]["heater_bed"]["target"];
float fileProgress = (float)(*jsonDoc)["result"]["status"]["virtual_sdcard"]["progress"];
printerData.progressFilepos = (const char*)(*jsonDoc)["result"]["status"]["virtual_sdcard"]["file_position"];
printerData.estimatedPrintTime = (float)(*jsonDoc)["result"]["status"]["toolhead"]["estimated_print_time"];
//printerData.progressFilepos = (const char*)(*jsonDoc)["result"]["status"]["virtual_sdcard"]["file_position"];
printerData->estimatedPrintTime = (float)(*jsonDoc)["result"]["status"]["toolhead"]["estimated_print_time"];
/*
printerData.progressPrintTimeLeft : No metadata is available, print duration and progress can be used to calculate the ETA:
*/
float totalPrintTime = printerData.progressPrintTime.toFloat() / fileProgress;
printerData.progressPrintTimeLeft = String(totalPrintTime - printerData.progressPrintTime.toFloat());
//float totalPrintTime = printerData.progressPrintTime.toFloat() / fileProgress;
//printerData.progressPrintTimeLeft = String(totalPrintTime - printerData.progressPrintTime.toFloat());
if (BasePrinterClientImpl::isOperational()) {
this->debugController->printLn("Status: " + this->getStateAsText() + " " + printerData.fileName + "(" + printerData.progressCompletion + "%)");
if (this->isOperational(printerData)) {
this->debugController->printLn("Status: "
+ this->globalDataController->getPrinterStateAsText(printerData) + " "
+ String(printerData->fileName) + "("
+ String(printerData->progressCompletion) + "%)"
);
}
}
void KlipperClient::getPrinterPsuState() {
/*// get the PSU state (if enabled and printer operational)
if (pollPsu && BasePrinterClientImpl::isOperational()) {
if (!validate()) {
printerData.isPSUoff = false; // we do not know PSU state, so assume on.
return;
}
String apiPostData = "POST /api/plugin/psucontrol HTTP/1.1";
String apiPostBody = "{\"command\":\"getPSUState\"}";
WiFiClient printClient = getPostRequest(apiPostData,apiPostBody);
if (printerData.error != "") {
printerData.isPSUoff = false; // we do not know PSU state, so assume on.
return;
}
const size_t bufferSize3 = JSON_OBJECT_SIZE(2) + 300;
DynamicJsonDocument jsonBuffer(bufferSize3);
// Parse JSON object
DeserializationError error = deserializeJson(jsonBuffer, printClient);
if (error) {
printerData.isPSUoff = false; // we do not know PSU state, so assume on
return;
}
String psu = (const char*)jsonBuffer["isPSUOn"];
if (psu == "true") {
printerData.isPSUoff = false; // PSU checked and is on
} else {
printerData.isPSUoff = true; // PSU checked and is off, set flag
}
printClient.stop(); //stop client
} else {
printerData.isPSUoff = false; // we are not checking PSU state, so assume on
} */
/**
* @brief Refresh psu state data for printer
* @param printerData Handle to printer struct
*/
void KlipperClient::getPrinterPsuState(PrinterDataStruct *printerData) {
}
/**

View File

@ -6,18 +6,15 @@
#include "BasePrinterClientImpl.h"
#include "../Global/GlobalDataController.h"
/**
* @brief KLIPPER Client implementation
*/
class KlipperClient : public BasePrinterClientImpl {
private:
boolean pollPsu;
boolean validate();
public:
KlipperClient(GlobalDataController *globalDataController, DebugController *debugController, JsonRequestClient *jsonRequestClient);
void getPrinterJobResults(PrinterDataStruct *printerData) override;
void getPrinterPsuState(PrinterDataStruct *printerData) override;
void getPrinterJobResults() override;
void getPrinterPsuState() override;
void updatePrintClient() override;
int translateState(String stateText);
private:
static int translateState(String stateText);
};

View File

@ -3,50 +3,35 @@
#include "OctoPrintClient.h"
/**
* @brief Construct a new OctoPrint Client:: OctoPrint Client object
*
* @param globalDataController Handle to global data controller
* @param debugController Handle to debug controller
* @param jsonRequestClient Handle to json request instance
*/
OctoPrintClient::OctoPrintClient(GlobalDataController *globalDataController, DebugController *debugController, JsonRequestClient *jsonRequestClient)
: BasePrinterClientImpl("Klipper", globalDataController, debugController, jsonRequestClient) {
this->updatePrintClient();
: BasePrinterClientImpl("OctoPrint", globalDataController, debugController, jsonRequestClient) {
}
void OctoPrintClient::updatePrintClient() {
encodedAuth = "";
if (this->globalDataController->getPrinterAuthUser() != "") {
String userpass = this->globalDataController->getPrinterAuthUser() + ":" + this->globalDataController->getPrinterAuthPass();
base64 b64;
encodedAuth = b64.encode(userpass, true);
}
pollPsu = this->globalDataController->hasPrinterPsu();
}
boolean OctoPrintClient::validate() {
boolean rtnValue = false;
printerData.error = "";
if ((this->globalDataController->getPrinterServer() == "") && (this->globalDataController->getPrinterHostName() == "")) {
printerData.error += "Server address or host name is required; ";
}
if (this->globalDataController->getPrinterApiKey() == "") {
printerData.error += "ApiKey is required; ";
}
if (printerData.error == "") {
rtnValue = true;
}
return rtnValue;
}
void OctoPrintClient::getPrinterJobResults() {
/**
* @brief Refresh job and state data for printer
* @param printerData Handle to printer struct
*/
void OctoPrintClient::getPrinterJobResults(PrinterDataStruct *printerData) {
const size_t bufferSize = 1414; // according to ArduinoJson assistant
DynamicJsonDocument *jsonDoc;
if (!validate()) {
if (!this->isValidConfig(printerData)) {
return;
}
// Req 1
this->debugController->printLn("Get OctoPrint Data: " + this->getInstanceServerTarget() + ":" + String(this->getInstanceServerPort()));
this->debugController->printLn("Get OctoPrint Data: " + String(printerData->remoteAddress) + ":" + String(printerData->remotePort));
jsonDoc = this->jsonRequestClient->requestJson(
PRINTER_REQUEST_GET,
this->getInstanceServerTarget(),
this->getInstanceServerPort(),
this->encodedAuth,
String(printerData->remoteAddress),
printerData->remotePort,
String(printerData->encAuth),
"/api/job",
"",
bufferSize,
@ -54,89 +39,62 @@ void OctoPrintClient::getPrinterJobResults() {
);
if (this->jsonRequestClient->getLastError() != "") {
this->debugController->printLn(this->jsonRequestClient->getLastError());
printerData.error = this->jsonRequestClient->getLastError();
printerData.state = PRINTER_STATE_OFFLINE;
printerData.isPrinting = false;
printerData.toolTemp = "";
printerData.toolTargetTemp = "";
printerData.bedTemp = "";
printerData.bedTargetTemp = "";
BasePrinterClient::resetPrinterData(printerData);
if (this->jsonRequestClient->getLastError().indexOf("PARSER") == 0) {
MemoryHelper::stringToChar(this->jsonRequestClient->getLastError(), printerData->error, 120);
printerData->state = PRINTER_STATE_ERROR;
}
return;
}
printerData.averagePrintTime = (const char*)(*jsonDoc)["job"]["averagePrintTime"];
printerData.estimatedPrintTime = (const char*)(*jsonDoc)["job"]["estimatedPrintTime"];
printerData.fileName = (const char*)(*jsonDoc)["job"]["file"]["name"];
printerData.fileSize = (const char*)(*jsonDoc)["job"]["file"]["size"];
printerData.lastPrintTime = (const char*)(*jsonDoc)["job"]["lastPrintTime"];
printerData.progressCompletion = (const char*)(*jsonDoc)["progress"]["completion"];
printerData.progressFilepos = (const char*)(*jsonDoc)["progress"]["filepos"];
printerData.progressPrintTime = (const char*)(*jsonDoc)["progress"]["printTime"];
printerData.progressPrintTimeLeft = (const char*)(*jsonDoc)["progress"]["printTimeLeft"];
printerData.filamentLength = (const char*)(*jsonDoc)["job"]["filament"]["tool0"]["length"];
printerData.state = this->translateState((const char*)(*jsonDoc)["state"]);
printerData->state = OctoPrintClient::translateState((const char*)(*jsonDoc)["state"]);
//printerData.averagePrintTime = (const char*)(*jsonDoc)["job"]["averagePrintTime"];
//printerData.estimatedPrintTime = (const char*)(*jsonDoc)["job"]["estimatedPrintTime"];
//printerData.fileName = (const char*)(*jsonDoc)["job"]["file"]["name"];
//printerData.fileSize = (const char*)(*jsonDoc)["job"]["file"]["size"];
//printerData.lastPrintTime = (const char*)(*jsonDoc)["job"]["lastPrintTime"];
//printerData.progressCompletion = (const char*)(*jsonDoc)["progress"]["completion"];
//printerData.progressFilepos = (const char*)(*jsonDoc)["progress"]["filepos"];
//printerData.progressPrintTime = (const char*)(*jsonDoc)["progress"]["printTime"];
//printerData.progressPrintTimeLeft = (const char*)(*jsonDoc)["progress"]["printTimeLeft"];
//printerData.filamentLength = (const char*)(*jsonDoc)["job"]["filament"]["tool0"]["length"];
if (BasePrinterClientImpl::isOperational()) {
this->debugController->printLn("Status: " + this->getStateAsText());
if (this->isOperational(printerData)) {
this->debugController->printLn("Status: " + this->globalDataController->getPrinterStateAsText(printerData));
} else {
this->debugController->printLn("Printer Not Operational");
}
// Req 2
jsonDoc = this->jsonRequestClient->requestJson(
PRINTER_REQUEST_GET,
this->getInstanceServerTarget(),
this->getInstanceServerPort(),
this->encodedAuth,
"/api/printer?exclude=sd,history",
"",
bufferSize,
true
);
if (this->jsonRequestClient->getLastError() != "") {
this->debugController->printLn(this->jsonRequestClient->getLastError());
printerData.error = this->jsonRequestClient->getLastError();
printerData.state = PRINTER_STATE_OFFLINE;
printerData.isPrinting = false;
printerData.toolTemp = "";
printerData.toolTargetTemp = "";
printerData.bedTemp = "";
printerData.bedTargetTemp = "";
return;
}
String printing = (const char*)(*jsonDoc)["state"]["flags"]["printing"];
if (printing == "true") {
printerData.isPrinting = true;
} else {
printerData.isPrinting = false;
}
printerData.toolTemp = (const char*)(*jsonDoc)["temperature"]["tool0"]["actual"];
printerData.toolTargetTemp = (const char*)(*jsonDoc)["temperature"]["tool0"]["target"];
printerData.bedTemp = (const char*)(*jsonDoc)["temperature"]["bed"]["actual"];
printerData.bedTargetTemp = (const char*)(*jsonDoc)["temperature"]["bed"]["target"];
if (BasePrinterClientImpl::isOperational()) {
this->debugController->printLn("Status: " + this->getStateAsText() + " " + printerData.fileName + "(" + printerData.progressCompletion + "%)");
if (this->isOperational(printerData)) {
this->debugController->printLn("Status: "
+ this->globalDataController->getPrinterStateAsText(printerData) + " "
+ String(printerData->fileName) + "("
+ String(printerData->progressCompletion) + "%)"
);
}
}
void OctoPrintClient::getPrinterPsuState() {
/**
* @brief Refresh psu state data for printer
* @param printerData Handle to printer struct
*/
void OctoPrintClient::getPrinterPsuState(PrinterDataStruct *printerData) {
const size_t bufferSize = 364; // according to ArduinoJson assistant
DynamicJsonDocument *jsonDoc;
// get the PSU state (if enabled and printer operational)
if (pollPsu && BasePrinterClientImpl::isOperational()) {
if (!validate()) {
printerData.isPSUoff = false; // we do not know PSU state, so assume on.
if (printerData->hasPsuControl && this->isOperational(printerData)) {
if (!this->isValidConfig(printerData)) {
// we do not know PSU state, so assume on.
printerData->isPSUoff = false;
return;
}
// Req 2
jsonDoc = this->jsonRequestClient->requestJson(
PRINTER_REQUEST_POST,
this->getInstanceServerTarget(),
this->getInstanceServerPort(),
this->encodedAuth,
String(printerData->remoteAddress),
printerData->remotePort,
String(printerData->encAuth),
"/api/plugin/psucontrol",
"{\"command\":\"getPSUState\"}",
bufferSize,
@ -144,18 +102,18 @@ void OctoPrintClient::getPrinterPsuState() {
);
if (this->jsonRequestClient->getLastError() != "") {
// we do not know PSU state, so assume on.
printerData.isPSUoff = false;
printerData->isPSUoff = false;
return;
}
String psu = (const char*)(*jsonDoc)["isPSUOn"];
if (psu == "true") {
printerData.isPSUoff = false; // PSU checked and is on
printerData->isPSUoff = false; // PSU checked and is on
} else {
printerData.isPSUoff = true; // PSU checked and is off, set flag
printerData->isPSUoff = true; // PSU checked and is off, set flag
}
} else {
printerData.isPSUoff = false; // we are not checking PSU state, so assume on
printerData->isPSUoff = false; // we are not checking PSU state, so assume on
}
}

View File

@ -6,18 +6,15 @@
#include "BasePrinterClientImpl.h"
#include "../Global/GlobalDataController.h"
/**
* @brief OCTOPRINT Client implementation
*/
class OctoPrintClient : public BasePrinterClientImpl {
private:
boolean pollPsu;
boolean validate();
public:
OctoPrintClient(GlobalDataController *globalDataController, DebugController *debugController, JsonRequestClient *jsonRequestClient);
void getPrinterJobResults(PrinterDataStruct *printerData) override;
void getPrinterPsuState(PrinterDataStruct *printerData) override;
void getPrinterJobResults() override;
void getPrinterPsuState() override;
void updatePrintClient() override;
int translateState(String stateText);
private:
static int translateState(String stateText);
};

View File

@ -10,24 +10,39 @@
#define PRINTER_STATE_PAUSED (int)2
#define PRINTER_STATE_COMPLETED (int)3
#define PRINTER_CLIENT_DUET (int)0
#define PRINTER_CLIENT_KLIPPER (int)1
#define PRINTER_CLIENT_OCTOPRINT (int)2
#define PRINTER_CLIENT_REPETIER (int)3
typedef struct {
String averagePrintTime;
String estimatedPrintTime;
String fileName;
String fileSize;
String lastPrintTime;
String progressCompletion;
String progressFilepos;
String progressPrintTime;
String progressPrintTimeLeft;
int state;
String toolTemp;
String toolTargetTemp;
String filamentLength;
String bedTemp;
String bedTargetTemp;
boolean isPrinting;
boolean isPSUoff;
String error;
String printerName;
} PrinterDataStruct;
char customName[20];
int apiType;
char apiKey[60];
char remoteAddress[60];
int remotePort;
bool basicAuthNeeded;
char basicAuthUsername[30];
char basicAuthPassword[60];
bool hasPsuControl;
long lastSyncEpoch;
char encAuth[120];
int averagePrintTime;
int estimatedPrintTime;
char fileName[60];
int fileSize;
int lastPrintTime;
char progressCompletion[60];
int progressFilepos;
int progressPrintTime;
int progressPrintTimeLeft;
int state;
float toolTemp;
float toolTargetTemp;
float filamentLength;
float bedTemp;
float bedTargetTemp;
bool isPrinting;
bool isPSUoff;
char error[120];
} PrinterDataStruct;

View File

@ -0,0 +1,36 @@
//
// ArduinoJSON Assistant: https://arduinojson.org/v6/assistant/
#include "RepetierClient.h"
/**
* @brief Construct a new Repetier Client:: Repetier Client object
*
* @param globalDataController Handle to global data controller
* @param debugController Handle to debug controller
* @param jsonRequestClient Handle to json request instance
*/
RepetierClient::RepetierClient(GlobalDataController *globalDataController, DebugController *debugController, JsonRequestClient *jsonRequestClient)
: BasePrinterClientImpl("Repetier", globalDataController, debugController, jsonRequestClient) {
}
/**
* @brief Refresh job and state data for printer
* @param printerData Handle to printer struct
*/
void RepetierClient::getPrinterJobResults(PrinterDataStruct *printerData) {
}
/**
* @brief Refresh psu state data for printer
* @param printerData Handle to printer struct
*/
void RepetierClient::getPrinterPsuState(PrinterDataStruct *printerData) {
}
/**
* We translate the avail states
*/
int RepetierClient::translateState(String stateText) {
return PRINTER_STATE_OFFLINE;
}

View File

@ -0,0 +1,20 @@
#pragma once
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
#include <base64.h>
#include "Debug.h"
#include "BasePrinterClientImpl.h"
#include "../Global/GlobalDataController.h"
/**
* @brief REPETIER Client implementation
*/
class RepetierClient : public BasePrinterClientImpl {
public:
RepetierClient(GlobalDataController *globalDataController, DebugController *debugController, JsonRequestClient *jsonRequestClient);
void getPrinterJobResults(PrinterDataStruct *printerData) override;
void getPrinterPsuState(PrinterDataStruct *printerData) override;
private:
static int translateState(String stateText);
};

View File

@ -5,16 +5,18 @@
#pragma once
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include "Clients/Clients.h"
/**
* Basic software settings
*/
#define VERSION "1.0"
#define HOSTNAME "PrintBuddy-"
#define CONFIG "/conf.txt"
// true = Enables debug message on terminal | false = disable all debug messages
#define DEBUG_MODE_ENABLE true
#define CONFIG "/conf.txt" // EEProm config file for general settings
#define PRINTERCONFIG "/pconf.txt" // EEProm config file for printer settings
#define DEBUG_MODE_ENABLE true // true = Enables debug message on terminal | false = disable all debug messages
#define MAX_PRINTERS 10 // Limit of configurable printers, please not that many printers slow down the system!
#define PRINTER_SYNC_SEC 60 // Snyc printer when offline or not printing every x seconds
#define PRINTER_SYNC_SEC_PRINTING 10 // Snyc printer when printing every x seconds
//===========================================================================
//========================= MCU & Display config ============================
@ -62,35 +64,6 @@
// true = System LED will Flash on Service Calls; false = disabled LED flashing
#define USE_FLASH true
//===========================================================================
//========================== Client for requests ============================
//===========================================================================
/**
* Printer client selection
* Use one of following (defined in Clients/Clients.h):
* DUET_CLIENT
* KLIPPER_CLIENT
* REPETIER_CLIENT
* OCTOPRINT_CLIENT
*/
#define PRINTERCLIENT KLIPPER_CLIENT
// Default: ApiKey from your User Account on client endpoint
#define PRINTERCLIENT_APIKEY ""
// Default: HostName from your client endpoint
#define PRINTERCLIENT_HOSTNAME ""
// Default: server ip (withot http://) for client endpoint
#define PRINTERCLIENT_SERVER ""
// Default: The port you are running your client server on (usually 80)
#define PRINTERCLIENT_PORT 80
// Default: Only used if you have haproxy or basic athentintication turned on (not default)
#define PRINTERCLIENT_AUTHUSER ""
// Default: Only used with haproxy or basic auth (only needed if you must authenticate)
#define PRINTERCLIENT_AUTHPASS ""
// Default: Set to true if https://github.com/kantlivelong/OctoPrint-PSUControl/ in use
#define PRINTERCLIENT_HASPSU false
//===========================================================================
//=========================== Webserver config ==============================
//===========================================================================

View File

@ -26,7 +26,7 @@ void NextionDisplay::flipDisplayUpdate() {
void NextionDisplay::showBootScreen() {
String command("version.txt=");
command += "\"for " + this->globalDataController->getPrinterClient()->getPrinterType() + " V" + this->globalDataController->getVersion() + "\"";
//command += "\"for " + this->globalDataController->getPrinterClient()->getPrinterType() + " V" + this->globalDataController->getSystemSettings()->version + "\"";
this->sendCommand("page 0");
this->sendCommand(command.c_str());
}

View File

@ -9,7 +9,7 @@ OledDisplay::OledDisplay(OLEDDisplay *oledDisplay, GlobalDataController *globalD
void OledDisplay::preSetup() {
this->oledDisplay->init();
if (this->globalDataController->isDisplayInverted()) {
if (this->globalDataController->getSystemSettings()->invertDisplay) {
this->oledDisplay->flipScreenVertically(); // connections at top of OLED display
}
this->oledDisplay->clear();
@ -36,7 +36,7 @@ void OledDisplay::postSetup() {
// Inital UI takes care of initalising the display too.
this->ui->init();
if (this->globalDataController->isDisplayInverted()) {
if (this->globalDataController->getSystemSettings()->invertDisplay) {
this->oledDisplay->flipScreenVertically(); // connections at top of OLED display
}
}
@ -48,7 +48,7 @@ void OledDisplay::handleUpdate() {
void OledDisplay::flipDisplayUpdate() {
this->ui->init();
if (this->globalDataController->isDisplayInverted()) {
if (this->globalDataController->getSystemSettings()->invertDisplay) {
this->oledDisplay->flipScreenVertically(); // connections at top of OLED display
}
this->ui->update();
@ -60,10 +60,10 @@ void OledDisplay::showBootScreen() {
this->oledDisplay->setFont(ArialMT_Plain_16);
this->oledDisplay->drawString(64, 1, "PrintBuddy");
this->oledDisplay->setFont(ArialMT_Plain_10);
this->oledDisplay->drawString(64, 18, "for " + this->globalDataController->getPrinterClient()->getPrinterType());
this->oledDisplay->drawString(64, 18, "for ");
this->oledDisplay->setFont(ArialMT_Plain_16);
this->oledDisplay->drawString(64, 30, "By XXXXXX");
this->oledDisplay->drawString(64, 46, "V" + this->globalDataController->getVersion());
this->oledDisplay->drawString(64, 46, "V" + this->globalDataController->getSystemSettings()->version);
this->oledDisplay->display();
}
@ -82,7 +82,7 @@ void OledDisplay::showApAccessScreen(String apSsid, String apIp) {
void OledDisplay::showWebserverSplashScreen(bool isEnabled) {
if (isEnabled) {
String webAddress = "http://" + WiFi.localIP().toString() + ":" + String(this->globalDataController->getWebserverPort()) + "/";
String webAddress = "http://" + WiFi.localIP().toString() + ":" + String(this->globalDataController->getSystemSettings()->webserverPort) + "/";
this->debugController->printLn("Use this URL : " + webAddress);
this->oledDisplay->clear();
this->oledDisplay->setTextAlignment(TEXT_ALIGN_CENTER);
@ -91,7 +91,7 @@ void OledDisplay::showWebserverSplashScreen(bool isEnabled) {
this->oledDisplay->drawString(64, 20, "You May Connect to IP");
this->oledDisplay->setFont(ArialMT_Plain_16);
this->oledDisplay->drawString(64, 30, WiFi.localIP().toString());
this->oledDisplay->drawString(64, 46, "Port: " + String(this->globalDataController->getWebserverPort()));
this->oledDisplay->drawString(64, 46, "Port: " + String(this->globalDataController->getSystemSettings()->webserverPort));
this->oledDisplay->display();
} else {
this->debugController->printLn("Web Interface is Disabled");
@ -112,12 +112,12 @@ void OledDisplay::showWebserverSplashScreen(bool isEnabled) {
void OledDisplay::checkDisplay() {
BasePrinterClient *printerClient = this->globalDataController->getPrinterClient();
//BasePrinterClient *printerClient = this->globalDataController->getPrinterClient();
if (!this->displayOn && this->globalDataController->getDisplayClock()) {
if (!this->displayOn && this->globalDataController->getClockSettings()->show) {
this->enableDisplay(true);
}
if (this->displayOn && !printerClient->isPrinting() && !this->globalDataController->getDisplayClock()) {
/*if (this->displayOn && !printerClient->isPrinting() && !this->globalDataController->getClockSettings()->show) {
// Put Display to sleep
this->oledDisplay->clear();
this->oledDisplay->display();
@ -130,7 +130,7 @@ void OledDisplay::checkDisplay() {
this->enableDisplay(false);
this->debugController->printLn("Printer is offline going down to sleep...");
return;
} else if (!this->displayOn && !this->globalDataController->getDisplayClock()) {
} else if (!this->displayOn && !this->globalDataController->getClockSettings()->show) {
if (printerClient->isOperational()) {
// Wake the Screen up
this->enableDisplay(true);
@ -145,7 +145,7 @@ void OledDisplay::checkDisplay() {
delay(5000);
return;
}
} else if (this->globalDataController->getDisplayClock()) {
} else if (this->globalDataController->getClockSettings()->show) {
if ((!printerClient->isPrinting() || printerClient->isPSUoff()) && !this->isClockOn) {
this->debugController->printLn("Clock Mode is turned on.");
if (!DISPLAYWEATHER) {
@ -164,14 +164,14 @@ void OledDisplay::checkDisplay() {
this->ui->enableAutoTransition();
isClockOn = false;
}
}
}*/
}
void OledDisplay::enableDisplay(boolean enable) {
this->displayOn = enable;
TimeClient * timeClient = this->globalDataController->getTimeClient();
if (enable) {
if (timeClient->getMinutesFromLast(this->displayOffEpoch) >= this->globalDataController->getClockResyncMinutes()) {
if (timeClient->getMinutesFromLast(this->displayOffEpoch) >= this->globalDataController->getSystemSettings()->clockWeatherResyncMinutes) {
// The display has been off longer than the minutes between refresh -- need to get fresh data
timeClient->resetLastEpoch();
this->displayOffEpoch = 0; // reset
@ -190,13 +190,13 @@ void OledDisplay::enableDisplay(boolean enable) {
}
void OledDisplay::drawScreen1(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
BasePrinterClient *printerClient = this->globalDataController->getPrinterClient();
//BasePrinterClient *printerClient = this->globalDataController->getPrinterClient();
String bed = printerClient->getValueRounded(printerClient->getTempBedActual());
String tool = printerClient->getValueRounded(printerClient->getTempToolActual());
//String bed = printerClient->getValueRounded(printerClient->getTempBedActual());
//String tool = printerClient->getValueRounded(printerClient->getTempToolActual());
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(ArialMT_Plain_16);
if (bed != "0") {
/*if (bed != "0") {
display->drawString(29 + x, 0 + y, "Tool");
display->drawString(89 + x, 0 + y, "Bed");
} else {
@ -211,11 +211,11 @@ void OledDisplay::drawScreen1(OLEDDisplay *display, OLEDDisplayUiState* state, i
} else {
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->drawString(64 + x, 14 + y, tool + "°");
}
}*/
}
void OledDisplay::drawScreen2(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
BasePrinterClient *printerClient = this->globalDataController->getPrinterClient();
//BasePrinterClient *printerClient = this->globalDataController->getPrinterClient();
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(ArialMT_Plain_16);
@ -223,7 +223,7 @@ void OledDisplay::drawScreen2(OLEDDisplay *display, OLEDDisplayUiState* state, i
display->drawString(64 + x, 0 + y, "Time Remaining");
//display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(ArialMT_Plain_24);
int val = printerClient->getProgressPrintTimeLeft().toInt();
/*int val = printerClient->getProgressPrintTimeLeft().toInt();
int hours = this->globalDataController->numberOfHours(val);
int minutes = this->globalDataController->numberOfMinutes(val);
int seconds = this->globalDataController->numberOfSeconds(val);
@ -231,11 +231,11 @@ void OledDisplay::drawScreen2(OLEDDisplay *display, OLEDDisplayUiState* state, i
String time = this->globalDataController->zeroPad(hours) + ":" +
this->globalDataController->zeroPad(minutes) + ":" +
this->globalDataController->zeroPad(seconds);
display->drawString(64 + x, 14 + y, time);
display->drawString(64 + x, 14 + y, time); */
}
void OledDisplay::drawScreen3(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
BasePrinterClient *printerClient = this->globalDataController->getPrinterClient();
/*BasePrinterClient *printerClient = this->globalDataController->getPrinterClient();
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(ArialMT_Plain_16);
@ -251,17 +251,17 @@ void OledDisplay::drawScreen3(OLEDDisplay *display, OLEDDisplayUiState* state, i
String time = this->globalDataController->zeroPad(hours) + ":" +
this->globalDataController->zeroPad(minutes) + ":" +
this->globalDataController->zeroPad(seconds);
display->drawString(64 + x, 14 + y, time);
display->drawString(64 + x, 14 + y, time); */
}
void OledDisplay::drawClock(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
TimeClient * timeClient = this->globalDataController->getTimeClient();
BasePrinterClient *printerClient = this->globalDataController->getPrinterClient();
/*BasePrinterClient *printerClient = this->globalDataController->getPrinterClient();
display->setTextAlignment(TEXT_ALIGN_CENTER);
String displayTime = timeClient->getAmPmHours() + ":" + timeClient->getMinutes() + ":" + timeClient->getSeconds();
if (this->globalDataController->getClockIs24h()) {
if (this->globalDataController->getClockSettings()->is24h) {
displayTime = timeClient->getHours() + ":" + timeClient->getMinutes() + ":" + timeClient->getSeconds();
}
String displayName = this->globalDataController->getPrinterHostName();
@ -271,7 +271,7 @@ void OledDisplay::drawClock(OLEDDisplay *display, OLEDDisplayUiState* state, int
display->setFont(ArialMT_Plain_16);
display->drawString(64 + x, 0 + y, displayName);
display->setFont(ArialMT_Plain_24);
display->drawString(64 + x, 17 + y, displayTime);
display->drawString(64 + x, 17 + y, displayTime); */
}
void OledDisplay::drawWeather(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
@ -290,19 +290,19 @@ void OledDisplay::drawWeather(OLEDDisplay *display, OLEDDisplayUiState* state, i
}
void OledDisplay::drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) {
TimeClient * timeClient = this->globalDataController->getTimeClient();
/*TimeClient * timeClient = this->globalDataController->getTimeClient();
BasePrinterClient *printerClient = this->globalDataController->getPrinterClient();
display->setColor(WHITE);
display->setFont(ArialMT_Plain_16);
String displayTime = timeClient->getAmPmHours() + ":" + timeClient->getMinutes();
if (this->globalDataController->getClockIs24h()) {
if (this->globalDataController->getClockSettings()->is24h) {
displayTime = timeClient->getHours() + ":" + timeClient->getMinutes();
}
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(0, 48, displayTime);
if (!this->globalDataController->getClockIs24h()) {
if (!this->globalDataController->getClockSettings()->is24h) {
String ampm = timeClient->getAmPm();
display->setFont(ArialMT_Plain_10);
display->drawString(39, 54, ampm);
@ -321,18 +321,18 @@ void OledDisplay::drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* st
display->drawHorizontalLine(0, 44, updatePos);
display->drawHorizontalLine(0, 45, updatePos);
this->drawRssi(display);
this->drawRssi(display); */
}
void OledDisplay::drawClockHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) {
TimeClient * timeClient = this->globalDataController->getTimeClient();
/*TimeClient * timeClient = this->globalDataController->getTimeClient();
BasePrinterClient *printerClient = this->globalDataController->getPrinterClient();
display->setColor(WHITE);
display->setFont(ArialMT_Plain_16);
display->setTextAlignment(TEXT_ALIGN_LEFT);
int printerStateDrawXPos = 0;
if (!this->globalDataController->getClockIs24h()) {
if (!this->globalDataController->getClockSettings()->is24h) {
display->drawString(0, 48, timeClient->getAmPm());
display->setTextAlignment(TEXT_ALIGN_CENTER);
printerStateDrawXPos = 64;
@ -347,11 +347,11 @@ void OledDisplay::drawClockHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiStat
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawRect(0, 43, 128, 2);
this->drawRssi(display);
this->drawRssi(display); */
}
void OledDisplay::drawRssi(OLEDDisplay *display) {
int8_t quality = this->globalDataController->getWifiQuality();
int8_t quality = EspController::getWifiQuality();
for (int8_t i = 0; i < 4; i++) {
for (int8_t j = 0; j < 3 * (i + 2); j++) {
if (quality > i * 25 || j == 0) {

View File

@ -0,0 +1,10 @@
#pragma once
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <base64.h>
typedef struct {
int utcOffset;
bool show;
bool is24h;
} ClockDataStruct;

View File

@ -0,0 +1,27 @@
#include "EspController.h"
/**
* @brief Get current WiFi Quality in percent
*
* @return int8_t
*/
int8_t EspController::getWifiQuality() {
int32_t dbm = WiFi.RSSI();
if(dbm <= -100) {
return 0;
} else if(dbm >= -50) {
return 100;
}
return 2 * (dbm + 100);
}
/**
* @brief Get heap memory stats for the esp
*
* @param hfree Free heap
* @param hmax Max continues blocks reserverd
* @param hfrag Heap fragmentation in percent
*/
void EspController::getHeap(uint32_t* hfree, uint16_t* hmax, uint8_t* hfrag) {
ESP.getHeapStats(hfree, hmax, hfrag);
}

View File

@ -0,0 +1,13 @@
#pragma once
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include "Configuration.h"
/**
* @brief Static only functions for control the ESP
*/
class EspController {
public:
static int8_t getWifiQuality();
static void getHeap(uint32_t* hfree, uint16_t* hmax, uint8_t* hfrag);
};

View File

@ -1,440 +1,469 @@
#include "GlobalDataController.h"
/**
* @brief Initialize class for all needed data
*/
GlobalDataController::GlobalDataController(TimeClient *timeClient, OpenWeatherMapClient *weatherClient, DebugController *debugController) {
this->timeClient = timeClient;
this->weatherClient = weatherClient;
this->debugController = debugController;
this->printers = (PrinterDataStruct *)malloc(1 * sizeof(PrinterDataStruct));
this->basePrinterClients = (BasePrinterClient**)malloc(1 * sizeof(int));
this->initDefaultConfig();
}
/**
* @brief Setup global controller
*/
void GlobalDataController::setup() {
this->listSettingFiles();
this->readSettings();
}
/**
* @brief List files in eeprom for debug
*/
void GlobalDataController::listSettingFiles() {
this->debugController->printLn("========= FileSystem Files =================");
Dir dir = LittleFS.openDir("/");
while (dir.next())
{
this->debugController->printLn(dir.fileName());
if(this->debugController->isEnabled()) {
this->debugController->printLn("========= FileSystem Files =================");
Dir dir = LittleFS.openDir("/");
while (dir.next())
{
this->debugController->printLn(dir.fileName());
}
}
}
/**
* @brief Read all setting from eeprom
*/
void GlobalDataController::readSettings() {
if (LittleFS.exists(CONFIG) == false) {
if ((LittleFS.exists(CONFIG) == false) || (LittleFS.exists(PRINTERCONFIG) == false)) {
this->debugController->printLn("Settings File does not yet exists.");
writeSettings();
this->writeSettings();
return;
}
// Read basic settings
File fr = LittleFS.open(CONFIG, "r");
String line;
while(fr.available()) {
line = fr.readStringUntil('\n');
this->readSettingsForInt(line, "printerCnt", &this->printersCnt);
this->readSettingsForBool(line, "systemInvertDisplay", &this->systemData.invertDisplay);
this->readSettingsForBool(line, "systemHasBasicAuth", &this->systemData.hasBasicAuth);
this->readSettingsForString(line, "systemWebserverUsername", &this->systemData.webserverUsername);
this->readSettingsForString(line, "systemWebserverPassword", &this->systemData.webserverPassword);
this->readSettingsForInt(line, "systemWebserverPort", &this->systemData.webserverPort);
this->readSettingsForBool(line, "systemUseLedFlash", &this->systemData.useLedFlash);
this->readSettingsForInt(line, "systemResyncMinutes", &this->systemData.clockWeatherResyncMinutes);
this->readSettingsForInt(line, "clockUtcOffset", &this->clockData.utcOffset);
this->readSettingsForBool(line, "clockShow", &this->clockData.show);
this->readSettingsForBool(line, "clockIs24h", &this->clockData.is24h);
this->readSettingsForBool(line, "weatherShow", &this->weatherData.show);
this->readSettingsForString(line, "weatherApiKey", &this->weatherData.apiKey);
this->readSettingsForBool(line, "weatherIsMetric", &this->weatherData.isMetric);
this->readSettingsForInt(line, "weatherCityId", &this->weatherData.cityId);
this->readSettingsForString(line, "weatherLang", &this->weatherData.lang);
}
fr.close();
if (line.indexOf("printerApiKey=") >= 0) {
this->PrinterApiKey = line.substring(line.lastIndexOf("printerApiKey=") + 14);
this->PrinterApiKey.trim();
this->debugController->printLn("PrinterApiKey=" + this->PrinterApiKey);
}
if (line.indexOf("printerHostName=") >= 0) {
this->PrinterHostName = line.substring(line.lastIndexOf("printerHostName=") + 16);
this->PrinterHostName.trim();
this->debugController->printLn("PrinterHostName=" + this->PrinterHostName);
}
if (line.indexOf("printerServer=") >= 0) {
this->PrinterServer = line.substring(line.lastIndexOf("printerServer=") + 14);
this->PrinterServer.trim();
this->debugController->printLn("PrinterServer=" + this->PrinterServer);
}
if (line.indexOf("printerPort=") >= 0) {
this->PrinterPort = line.substring(line.lastIndexOf("printerPort=") + 12).toInt();
this->debugController->printLn("PrinterPort=" + String(this->PrinterPort));
}
if (line.indexOf("printerName=") >= 0) {
String printer = line.substring(line.lastIndexOf("printerName=") + 12);
printer.trim();
this->getPrinterClient()->setPrinterName(printer);
this->debugController->printLn("PrinterName=" + this->getPrinterClient()->getPrinterName());
}
if (line.indexOf("printerAuthUser=") >= 0) {
this->PrinterAuthUser = line.substring(line.lastIndexOf("printerAuthUser=") + 16);
this->PrinterAuthUser.trim();
this->debugController->printLn("PrinterAuthUser=" + this->PrinterAuthUser);
}
if (line.indexOf("printerAuthPass=") >= 0) {
this->PrinterAuthPass = line.substring(line.lastIndexOf("printerAuthPass=") + 16);
this->PrinterAuthPass.trim();
this->debugController->printLn("PrinterAuthPass=" + this->PrinterAuthPass);
}
if (line.indexOf("printerHasPsu=") >= 0) {
this->PrinterHasPsu = line.substring(line.lastIndexOf("printerHasPsu=") + 14).toInt();
this->debugController->printLn("PrinterHasPsu=" + String(this->PrinterHasPsu));
}
if(line.indexOf("displayInvertDisplay=") >= 0) {
this->DisplayInvertDisplay = line.substring(line.lastIndexOf("displayInvertDisplay=") + 21).toInt();
this->debugController->printLn("DisplayInvertDisplay=" + String(this->DisplayInvertDisplay));
}
if (line.indexOf("webserverTheme=") >= 0) {
this->WebserverTheme = line.substring(line.lastIndexOf("webserverTheme=") + 15);
this->WebserverTheme.trim();
this->debugController->printLn("webserverTheme=" + this->WebserverTheme);
}
if (line.indexOf("webserverIsBasicAuth=") >= 0) {
this->WebserverIsBasicAuth = line.substring(line.lastIndexOf("webserverIsBasicAuth=") + 21).toInt();
this->debugController->printLn("webserverIsBasicAuth=" + String(this->WebserverIsBasicAuth));
}
if (line.indexOf("webserverUsername=") >= 0) {
this->WebserverUsername = line.substring(line.lastIndexOf("webserverUsername=") + 18);
this->WebserverUsername.trim();
this->debugController->printLn("webserverUsername=" + this->WebserverUsername);
}
if (line.indexOf("webserverPassword=") >= 0) {
this->WebserverPassword = line.substring(line.lastIndexOf("webserverPassword=") + 18);
this->WebserverPassword.trim();
this->debugController->printLn("webserverPassword=" + this->WebserverPassword);
}
if (line.indexOf("clockUtcOffset=") >= 0) {
this->ClockUtcOffset = line.substring(line.lastIndexOf("clockUtcOffset=") + 15).toFloat();
this->debugController->printLn("clockUtcOffset=" + String(this->ClockUtcOffset));
}
if (line.indexOf("clockResyncMinutes=") >= 0) {
this->ClockResyncMinutes = line.substring(line.lastIndexOf("clockResyncMinutes=") + 19).toInt();
this->debugController->printLn("clockResyncMinutes=" + String(this->ClockResyncMinutes));
}
if (line.indexOf("displayClock=") >= 0) {
this->DisplayClock = line.substring(line.lastIndexOf("displayClock=") + 13).toInt();
this->debugController->printLn("displayClock=" + String(this->DisplayClock));
}
if (line.indexOf("clockIs24h=") >= 0) {
this->ClockIs24h = line.substring(line.lastIndexOf("clockIs24h=") + 11).toInt();
this->debugController->printLn("clockIs24h=" + String(this->ClockIs24h));
}
if (line.indexOf("weatherShow=") >= 0) {
this->WeatherShow = line.substring(line.lastIndexOf("weatherShow=") + 12).toInt();
this->debugController->printLn("weatherShow=" + String(this->WeatherShow));
}
if (line.indexOf("weatherApiKey=") >= 0) {
this->WeatherApiKey = line.substring(line.lastIndexOf("weatherApiKey=") + 14);
this->WeatherApiKey.trim();
this->debugController->printLn("weatherApiKey=" + this->WeatherApiKey);
}
if (line.indexOf("weatherCityId=") >= 0) {
this->WeatherCityId = line.substring(line.lastIndexOf("weatherCityId=") + 14).toInt();
this->debugController->printLn("weatherCityId=" + String(this->WeatherCityId));
}
if (line.indexOf("weatherIsMetric=") >= 0) {
this->WeatherIsMetric = line.substring(line.lastIndexOf("weatherIsMetric=") + 16).toInt();
this->debugController->printLn("weatherIsMetric=" + String(this->WeatherIsMetric));
}
if (line.indexOf("weatherLang=") >= 0) {
this->WeatherLang = line.substring(line.lastIndexOf("weatherLang=") + 12);
this->WeatherLang.trim();
this->debugController->printLn("weatherLang=" + this->WeatherLang);
}
if(line.indexOf("useLedFlash=") >= 0) {
this->UseLedFlash = line.substring(line.lastIndexOf("useLedFlash=") + 12).toInt();
this->debugController->printLn("useLedFlash=" + String(this->UseLedFlash));
// Read printer settings
free(this->printers);
int mallocSize = this->printersCnt;
if (mallocSize == 0) {
mallocSize = 0;
}
this->printers = (PrinterDataStruct *)malloc(mallocSize * sizeof(PrinterDataStruct));
fr = LittleFS.open(PRINTERCONFIG, "r");
String searchName = "";
while(fr.available()) {
line = fr.readStringUntil('\n');
for(int i=0; i<this->printersCnt; i++) {
searchName = "printer" + String(i) + "_";
this->readSettingsForChar(line, searchName + "Name", this->printers[i].customName, 20);
this->readSettingsForInt(line, searchName + "ApiType", &this->printers[i].apiType);
this->readSettingsForChar(line, searchName + "ApiKey", this->printers[i].apiKey, 60);
this->readSettingsForChar(line, searchName + "RemAddr", this->printers[i].remoteAddress, 60);
this->readSettingsForInt(line, searchName + "RemPort", &this->printers[i].remotePort);
this->readSettingsForBool(line, searchName + "baNeed", &this->printers[i].basicAuthNeeded);
this->readSettingsForChar(line, searchName + "baUser", this->printers[i].basicAuthUsername, 30);
this->readSettingsForChar(line, searchName + "baPass", this->printers[i].basicAuthPassword, 60);
this->readSettingsForBool(line, searchName + "hasPsu", &this->printers[i].hasPsuControl);
}
}
fr.close();
this->getPrinterClient()->updatePrintClient();
this->weatherClient->updateWeatherApiKey(this->WeatherApiKey);
this->weatherClient->updateLanguage(this->WeatherLang);
this->weatherClient->setMetric(this->WeatherIsMetric);
this->weatherClient->updateCityId(this->WeatherCityId);
this->timeClient->setUtcOffset(this->getClockUtcOffset());
// Reset printer data
for(int i=0; i<this->printersCnt; i++) {
BasePrinterClient::resetPrinterData(&this->printers[i]);
}
// Trigger updates!
//this->getPrinterClient()->updatePrintClient();
this->weatherClient->updateWeatherApiKey(this->weatherData.apiKey);
this->weatherClient->updateLanguage(this->weatherData.lang);
this->weatherClient->setMetric(this->weatherData.isMetric);
this->weatherClient->updateCityId(this->weatherData.cityId);
this->timeClient->setUtcOffset(this->clockData.utcOffset);
}
/**
* @brief Set read setting line to char
*
* @param line Readed line from config
* @param expSearch Search expansion name
* @param targetChar Target char array
* @param maxLen Max size
* @return bool true = found | false = line not match
*/
bool GlobalDataController::readSettingsForChar(String line, String expSearch, char *targetChar, size_t maxLen) {
String searchName = expSearch +"=";
if (line.indexOf(searchName) >= 0) {
String readData = line.substring(line.lastIndexOf(searchName) + searchName.length());
readData.trim();
MemoryHelper::stringToChar(readData, targetChar, maxLen);
this->debugController->printLn(searchName + String(targetChar));
return true;
}
return false;
}
/**
* @brief Set read setting line to String
*
* @param line Readed line from config
* @param expSearch Search expansion name
* @param targetString Target String
* @return bool true = found | false = line not match
*/
bool GlobalDataController::readSettingsForString(String line, String expSearch, String *targetString) {
String searchName = expSearch +"=";
if (line.indexOf(searchName) >= 0) {
*targetString = line.substring(line.lastIndexOf(searchName) + searchName.length());
targetString->trim();
this->debugController->printLn(searchName + *targetString);
return true;
}
return false;
}
/**
* @brief Set read setting line to int
*
* @param line Readed line from config
* @param expSearch Search expansion name
* @param targetInt Target integer
* @return bool true = found | false = line not match
*/
bool GlobalDataController::readSettingsForInt(String line, String expSearch, int *targetInt) {
String searchName = expSearch +"=";
if (line.indexOf(searchName) >= 0) {
*targetInt = line.substring(line.lastIndexOf(searchName) + searchName.length()).toInt();
this->debugController->printLn(searchName + String(*targetInt));
return true;
}
return false;
}
/**
* @brief Set read setting line to bool
*
* @param line Readed line from config
* @param expSearch Search expansion name
* @param targetInt Target bool
* @return bool true = found | false = line not match
*/
bool GlobalDataController::readSettingsForBool(String line, String expSearch, bool *targetBool) {
int temp = 0;
if(this->readSettingsForInt(line, expSearch, &temp)) {
*targetBool = temp;
return true;
}
return false;
}
/**
* @brief Write all setting to eeprom
*/
void GlobalDataController::writeSettings() {
// Save decoded message to SPIFFS file for playback on power up.
// Store basic settings
File f = LittleFS.open(CONFIG, "w");
if (!f) {
this->debugController->printLn("File open failed!");
} else {
this->debugController->printLn("Saving settings now...");
f.println("printerApiKey=" + this->PrinterApiKey);
f.println("printerHostName=" + this->PrinterHostName);
f.println("printerServer=" + this->PrinterServer);
f.println("printerPort=" + String(this->PrinterPort));
f.println("printerName=" + this->getPrinterClient()->getPrinterName());
f.println("printerAuthUser=" + this->PrinterAuthUser);
f.println("printerAuthPass=" + this->PrinterAuthPass);
f.println("printerHasPsu=" + String(this->PrinterHasPsu));
f.println("displayInvertDisplay=" + String(this->DisplayInvertDisplay));
f.println("webserverTheme=" + this->WebserverTheme);
f.println("webserverIsBasicAuth=" + String(this->WebserverIsBasicAuth));
f.println("webserverUsername=" + String(this->WebserverUsername));
f.println("webserverPassword=" + String(this->WebserverPassword));
f.println("clockUtcOffset=" + String(this->ClockUtcOffset));
f.println("clockResyncMinutes=" + String(this->ClockResyncMinutes));
f.println("displayClock=" + String(this->DisplayClock));
f.println("clockIs24h=" + String(this->ClockIs24h));
f.println("weatherShow=" + String(this->WeatherShow));
f.println("weatherApiKey=" + this->WeatherApiKey);
f.println("weatherCityId=" + String(this->WeatherCityId));
f.println("weatherIsMetric=" + String(this->WeatherIsMetric));
f.println("weatherLang=" + this->WeatherLang);
f.println("useLedFlash=" + String(this->UseLedFlash));
this->debugController->printLn("Saving default settings now...");
f.println("printerCnt=" + String(this->printersCnt));
f.println("systemInvertDisplay=" + String(this->systemData.invertDisplay));
f.println("systemHasBasicAuth=" + String(this->systemData.hasBasicAuth));
f.println("systemWebserverUsername=" + this->systemData.webserverUsername);
f.println("systemWebserverPassword=" + this->systemData.webserverPassword);
f.println("systemWebserverPort=" + String(this->systemData.webserverPort));
f.println("systemUseLedFlash=" + String(this->systemData.useLedFlash));
f.println("systemResyncMinutes=" + String(this->systemData.clockWeatherResyncMinutes));
f.println("clockUtcOffset=" + String(this->clockData.utcOffset));
f.println("clockShow=" + String(this->clockData.show));
f.println("clockIs24h=" + String(this->clockData.is24h));
f.println("weatherShow=" + String(this->weatherData.show));
f.println("weatherApiKey=" + this->weatherData.apiKey);
f.println("weatherCityId=" + String(this->weatherData.cityId));
f.println("weatherIsMetric=" + String(this->weatherData.isMetric));
f.println("weatherLang=" + this->weatherData.lang);
}
f.close();
// Store printer settings
f = LittleFS.open(PRINTERCONFIG, "w");
if (!f) {
this->debugController->printLn("File open failed!");
} else {
this->debugController->printLn("Saving printer settings now...");
for(int i=0; i<this->printersCnt; i++) {
f.println("printer" + String(i) + "_Name=" + String(this->printers[i].customName));
f.println("printer" + String(i) + "_ApiType=" + String(this->printers[i].apiType));
f.println("printer" + String(i) + "_ApiKey=" + String(this->printers[i].apiKey));
f.println("printer" + String(i) + "_RemAddr=" + String(this->printers[i].remoteAddress));
f.println("printer" + String(i) + "_RemPort=" + String(this->printers[i].remotePort));
f.println("printer" + String(i) + "_baNeed=" + String(this->printers[i].basicAuthNeeded));
f.println("printer" + String(i) + "_baUser=" + String(this->printers[i].basicAuthUsername));
f.println("printer" + String(i) + "_baPass=" + String(this->printers[i].basicAuthPassword));
f.println("printer" + String(i) + "_hasPsu=" + String(this->printers[i].hasPsuControl));
}
}
f.close();
// Success, let us read all again to match
readSettings();
}
String GlobalDataController::getVersion() {
return VERSION;
/**
* @brief Intialize all internal data with parameters from <see ref="Configuration.h">
*/
void GlobalDataController::initDefaultConfig() {
this->systemData.clockWeatherResyncMinutes = TIME_RESYNC_MINUTES_DELAY;
this->systemData.hasBasicAuth = WEBSERVER_IS_BASIC_AUTH;
#ifdef DISPLAY_INVERT_DISPLAY
this->systemData.invertDisplay = DISPLAY_INVERT_DISPLAY;
#else
this->systemData.invertDisplay = false;
#endif
this->systemData.useLedFlash = USE_FLASH;
this->systemData.lastError = "";
this->systemData.version = VERSION;
this->systemData.webserverPassword = WEBSERVER_PASSWORD;
this->systemData.webserverPort = WEBSERVER_PORT;
this->systemData.webserverUsername = WEBSERVER_USERNAME;
this->clockData.is24h = TIME_IS_24HOUR;
this->clockData.show = DISPLAYCLOCK;
this->clockData.utcOffset = TIME_UTCOFFSET;
this->weatherData.apiKey = WEATHER_APIKEY;
this->weatherData.cityId = WEATHER_CITYID;
this->weatherData.isMetric = WEATHER_METRIC;
this->weatherData.lang = WEATHER_LANGUAGE;
this->weatherData.show = DISPLAYWEATHER;
}
String GlobalDataController::getLastReportStatus() {
return this->lastReportStatus;
/**
* @brief Delete configurations from eeprom
* @return bool true = success | false = error
*/
bool GlobalDataController::resetConfig() {
return LittleFS.remove(CONFIG) && LittleFS.remove(PRINTERCONFIG);
}
/**
* @brief Return internal reference to time client
* @return TimeClient*
*/
TimeClient *GlobalDataController::getTimeClient() {
return this->timeClient;
}
/**
* @brief Return internal reference to weather client
* @return OpenWeatherMapClient*
*/
OpenWeatherMapClient *GlobalDataController::getWeatherClient() {
return this->weatherClient;
}
void GlobalDataController::setPrinterClient(BasePrinterClient *basePrinterClient) {
this->basePrinterClient = basePrinterClient;
}
BasePrinterClient *GlobalDataController::getPrinterClient() {
return this->basePrinterClient;
/**
* @brief Set LED state
* @param value true = enable LED | false = disable LED
*/
void GlobalDataController::ledOnOff(boolean value) {
if (this->systemData.useLedFlash) {
if (value) {
digitalWrite(EXTERNAL_LED, LOW); // LED ON
} else {
digitalWrite(EXTERNAL_LED, HIGH); // LED OFF
}
}
}
/**
* @brief Cyclic LED flash
* @param number Number of cycles
* @param delayTime Delay between states
*/
void GlobalDataController::flashLED(int number, int delayTime) {
for (int inx = 0; inx <= number; inx++) {
delay(delayTime);
digitalWrite(EXTERNAL_LED, LOW); // ON
delay(delayTime);
digitalWrite(EXTERNAL_LED, HIGH); // OFF
delay(delayTime);
}
}
/**
* @brief Set handle to display
*
* @param baseDisplayClient
*/
void GlobalDataController::setDisplayClient(BaseDisplayClient *baseDisplayClient) {
this->baseDisplayClient = baseDisplayClient;
}
/**
* @brief Return handle to current display
*
* @return BaseDisplayClient*
*/
BaseDisplayClient *GlobalDataController::getDisplayClient() {
return this->baseDisplayClient;
}
/**
* Configuration parameters
* @brief Return current configuration for the system
*
* @return SystemDataStruct*
*/
String GlobalDataController::getPrinterApiKey() {
return this->PrinterApiKey;
}
void GlobalDataController::setPrinterApiKey(String printerApiKey) {
this->PrinterApiKey = printerApiKey;
}
String GlobalDataController::getPrinterHostName() {
return this->PrinterHostName;
}
void GlobalDataController::setPrinterHostName(String printerHostName) {
this->PrinterHostName = printerHostName;
}
String GlobalDataController::getPrinterServer() {
return this->PrinterServer;
}
void GlobalDataController::setPrinterServer(String printerServer) {
this->PrinterServer = printerServer;
}
int GlobalDataController::getPrinterPort() {
return this->PrinterPort;
}
void GlobalDataController::setPrinterPort(int printerPort) {
this->PrinterPort = printerPort;
}
String GlobalDataController::getPrinterAuthUser() {
return this->PrinterAuthUser;
}
void GlobalDataController::setPrinterAuthUser(String printerAuthUser) {
this->PrinterAuthUser = printerAuthUser;
}
String GlobalDataController::getPrinterAuthPass() {
return this->PrinterAuthPass;
}
void GlobalDataController::setPrinterAuthPass(String printerAuthPass) {
this->PrinterAuthPass = printerAuthPass;
}
bool GlobalDataController::hasPrinterPsu() {
return this->PrinterHasPsu;
}
void GlobalDataController::setHasPrinterPsu(bool hasPsu) {
this->PrinterHasPsu = hasPsu;
}
int GlobalDataController::getWebserverPort() {
return this->WebserverPort;
}
bool GlobalDataController::getWebserverIsBasicAuth() {
return this->WebserverIsBasicAuth;
}
void GlobalDataController::setWebserverIsBasicAuth(bool webserverIsBasicAuth) {
this->WebserverIsBasicAuth = webserverIsBasicAuth;
}
String GlobalDataController::getWebserverUsername() {
return this->WebserverUsername;
}
void GlobalDataController::setWebserverUsername(String webserverUsername) {
this->WebserverUsername = webserverUsername;
}
String GlobalDataController::getWebserverPassword() {
return this->WebserverPassword;
}
void GlobalDataController::setWebserverPassword(String webserverPassword) {
this->WebserverPassword = webserverPassword;
}
String GlobalDataController::getWebserverTheme() {
return this->WebserverTheme;
}
void GlobalDataController::setWebserverTheme(String webserverTheme) {
this->WebserverTheme = webserverTheme;
}
bool GlobalDataController::isDisplayInverted() {
return this->DisplayInvertDisplay;
}
void GlobalDataController::setIsDisplayInverted(bool displayInvertDisplay) {
this->DisplayInvertDisplay = displayInvertDisplay;
}
int GlobalDataController::getClockUtcOffset() {
return this->ClockUtcOffset;
}
void GlobalDataController::setClockUtcOffset(int clockUtcOffset) {
this->ClockUtcOffset = clockUtcOffset;
}
bool GlobalDataController::getDisplayClock() {
return this->DisplayClock;
}
void GlobalDataController::setDisplayClock(bool displayClock) {
this->DisplayClock = displayClock;
}
bool GlobalDataController::getClockIs24h() {
return this->ClockIs24h;
}
void GlobalDataController::setClockIs24h(bool clockIs24h) {
this->ClockIs24h = clockIs24h;
}
int GlobalDataController::getClockResyncMinutes() {
return this->ClockResyncMinutes;
}
void GlobalDataController::setClockResyncMinutes(int clockResyncMinutes) {
this->ClockResyncMinutes = clockResyncMinutes;
}
bool GlobalDataController::useLedFlash() {
return this->UseLedFlash;
}
void GlobalDataController::setUseLedFlash(bool useLedFlash) {
this->UseLedFlash = useLedFlash;
}
bool GlobalDataController::getWeatherShow() {
return this->WeatherShow;
}
void GlobalDataController::setWeatherShow(bool weatherShow) {
this->WeatherShow = weatherShow;
}
String GlobalDataController::getWeatherApiKey() {
return this->WeatherApiKey;
}
void GlobalDataController::setWeatherApiKey(String weatherApiKey) {
this->WeatherApiKey = weatherApiKey;
}
int GlobalDataController::getWeatherCityId() {
return this->WeatherCityId;
}
void GlobalDataController::setWeatherCityId(int weatherCityId) {
this->WeatherCityId = weatherCityId;
}
bool GlobalDataController::getWeatherIsMetric() {
return this->WeatherIsMetric;
}
void GlobalDataController::setWeatherIsMetric(bool weatherIsMetric) {
this->WeatherIsMetric = weatherIsMetric;
}
String GlobalDataController::getWeatherLang() {
return this->WeatherLang;
}
void GlobalDataController::setWeatherLang(String weatherLang) {
this->WeatherLang = weatherLang;
SystemDataStruct *GlobalDataController::getSystemSettings() {
return &this->systemData;
}
/**
* Notify LED
* @brief Return current configuration for the clock
* @return ClockDataStruct*
*/
ClockDataStruct *GlobalDataController::getClockSettings() {
return &this->clockData;
}
void GlobalDataController::ledOnOff(boolean value) {
if (this->useLedFlash()) {
if (value) {
digitalWrite(EXTERNAL_LED, LOW); // LED ON
} else {
digitalWrite(EXTERNAL_LED, HIGH); // LED OFF
/**
* @brief Return current configuration for the weather
* @return WeatherDataStruct*
*/
WeatherDataStruct *GlobalDataController::getWeatherSettings() {
return &this->weatherData;
}
/**
* @brief Returns number of printers in prntersettings
* @return int
*/
int GlobalDataController::getNumPrinters() {
return this->printersCnt;
}
/**
* @brief Return current configuration for the printers
* @return PrinterDataStruct*
*/
PrinterDataStruct *GlobalDataController::getPrinterSettings() {
return this->printers;
}
/**
* @brief Creates an new entry in printer setting table
* @return PrinterDataStruct* The new struct for the entry
*/
PrinterDataStruct *GlobalDataController::addPrinterSetting() {
int mallocSize = this->printersCnt + 1;
PrinterDataStruct *newStruct = (PrinterDataStruct *)malloc(mallocSize * sizeof(PrinterDataStruct));
if (this->printersCnt > 0) {
memcpy(newStruct, this->printers, this->printersCnt * sizeof(PrinterDataStruct));
}
}
}
void GlobalDataController::flashLED(int number, int delayTime) {
for (int inx = 0; inx <= number; inx++) {
delay(delayTime);
digitalWrite(EXTERNAL_LED, LOW); // ON
delay(delayTime);
digitalWrite(EXTERNAL_LED, HIGH); // OFF
delay(delayTime);
}
}
bool GlobalDataController::resetConfig() {
return LittleFS.remove(CONFIG);
free(this->printers);
this->printers = newStruct;
PrinterDataStruct *retStruct = &(this->printers[this->printersCnt]);
memset(retStruct, 0, sizeof(PrinterDataStruct));
this->printersCnt++;
return retStruct;
}
/**
* Global used functions
* @brief Return a printer state as readable text
* @param printerHandle Handle to printer data
* @return String
*/
String GlobalDataController::getPrinterStateAsText(PrinterDataStruct *printerHandle) {
switch (printerHandle->state)
{
case PRINTER_STATE_ERROR:
return "Error";
case PRINTER_STATE_STANDBY:
return "Standby";
case PRINTER_STATE_PRINTING:
return "Printing";
case PRINTER_STATE_PAUSED:
return "Paused";
case PRINTER_STATE_COMPLETED:
return "Completed";
default:
return "Offline";
}
}
int8_t GlobalDataController::getWifiQuality() {
int32_t dbm = WiFi.RSSI();
if(dbm <= -100) {
return 0;
} else if(dbm >= -50) {
return 100;
} else {
return 2 * (dbm + 100);
}
/**
* @brief Register an new printer client vor internal handling
*
* @param id Type ID
* @param basePrinterClient Client
*/
void GlobalDataController::registerPrinterClient(int id, BasePrinterClient *basePrinterClient) {
if (this->basePrinterCount < (id + 1)) {
BasePrinterClient** newSet = (BasePrinterClient**)malloc((id + 1) * sizeof(BasePrinterClient*));
memset(newSet, 0, (id + 1) * sizeof(BasePrinterClient*));
for (int i=0; i<this->basePrinterCount; i++) {
newSet[i] = this->basePrinterClients[i];
}
free(this->basePrinterClients);
this->basePrinterClients = newSet;
this->basePrinterCount = id + 1;
}
this->basePrinterClients[id] = basePrinterClient;
}
/**
* @brief Get viewable type of client for printer
* @param printerHandle Handle to printer data
* @return String
*/
String GlobalDataController::getPrinterClientType(PrinterDataStruct *printerHandle) {
for (int i=0; i<this->basePrinterCount; i++) {
if((i == printerHandle->apiType) && (this->basePrinterClients[i] != NULL)) {
return this->basePrinterClients[i]->getClientType();
}
}
return "Unknown";
}
/**
* @brief Sync printer with client
* @param printerHandle Handle to printer data
*/
void GlobalDataController::syncPrinter(PrinterDataStruct *printerHandle) {
for (int i=0; i<this->basePrinterCount; i++) {
if((i == printerHandle->apiType) && (this->basePrinterClients[i] != NULL)) {
if (this->basePrinterClients[i]->isValidConfig(printerHandle)) {
this->debugController->printLn("syncPrinter: " + String(printerHandle->lastSyncEpoch) + " | " + String(printerHandle->customName));
this->basePrinterClients[i]->getPrinterJobResults(printerHandle);
this->basePrinterClients[i]->getPrinterPsuState(printerHandle);
}
}
}
}

View File

@ -3,12 +3,22 @@
#include <ESP8266WiFi.h>
#include <LittleFS.h>
#include "Configuration.h"
#include "ClockDataStruct.h"
#include "SystemDataStruct.h"
#include "WeatherDataStruct.h"
#include "../Network/TimeClient.h"
#include "../Network/OpenWeatherMapClient.h"
#include "../Display/BaseDisplayClient.h"
#include "../Clients/BasePrinterClient.h"
#include "DebugController.h"
#include "../Display/BaseDisplayClient.h"
#include "../../include/MemoryHelper.h"
#include "EspController.h"
static const char ERROR_MESSAGES_ERR1[] PROGMEM = "[ERR1] Printer fo update not found!";
/**
* @brief Handles all needed data for all instances
*/
class GlobalDataController {
private:
/**
@ -16,41 +26,20 @@ private:
*/
String lastReportStatus = "";
TimeClient *timeClient;
BasePrinterClient *basePrinterClient;
OpenWeatherMapClient *weatherClient;
DebugController *debugController;
BaseDisplayClient *baseDisplayClient;
BasePrinterClient **basePrinterClients;
int basePrinterCount = 0;
/**
* Configuration variables
*/
String PrinterApiKey = PRINTERCLIENT_APIKEY;
String PrinterHostName = PRINTERCLIENT_HOSTNAME;
String PrinterServer = PRINTERCLIENT_SERVER;
int PrinterPort = PRINTERCLIENT_PORT;
String PrinterAuthUser = PRINTERCLIENT_AUTHUSER;
String PrinterAuthPass = PRINTERCLIENT_AUTHPASS;
bool PrinterHasPsu = PRINTERCLIENT_HASPSU;
int WebserverPort = WEBSERVER_PORT;
bool WebserverIsBasicAuth = WEBSERVER_IS_BASIC_AUTH;
String WebserverUsername = WEBSERVER_USERNAME;
String WebserverPassword = WEBSERVER_PASSWORD;
String WebserverTheme = WEBSERVER_THEMECOLOR;
int ClockUtcOffset = TIME_UTCOFFSET;
bool DisplayClock = DISPLAYCLOCK;
bool ClockIs24h = TIME_IS_24HOUR;
int ClockResyncMinutes = TIME_RESYNC_MINUTES_DELAY;
bool UseLedFlash = USE_FLASH;
bool WeatherShow = DISPLAYWEATHER;
String WeatherApiKey = WEATHER_APIKEY;
int WeatherCityId = WEATHER_CITYID;
bool WeatherIsMetric = WEATHER_METRIC;
String WeatherLang = WEATHER_LANGUAGE;
#ifdef DISPLAY_INVERT_DISPLAY
bool DisplayInvertDisplay = DISPLAY_INVERT_DISPLAY;
#else
bool DisplayInvertDisplay = false;
#endif
PrinterDataStruct *printers;
int printersCnt = 0;
SystemDataStruct systemData;
ClockDataStruct clockData;
WeatherDataStruct weatherData;
public:
GlobalDataController(TimeClient *timeClient, OpenWeatherMapClient *weatherClient, DebugController *debugController);
@ -58,74 +47,45 @@ public:
void listSettingFiles();
void readSettings();
void writeSettings();
void setPrinterClient(BasePrinterClient *basePrinterClient);
void setDisplayClient(BaseDisplayClient *baseDisplayClient);
SystemDataStruct *getSystemSettings();
ClockDataStruct *getClockSettings();
WeatherDataStruct *getWeatherSettings();
TimeClient *getTimeClient();
OpenWeatherMapClient *getWeatherClient();
BasePrinterClient *getPrinterClient();
BaseDisplayClient *getDisplayClient();
String getLastReportStatus();
String getVersion();
String getPrinterApiKey();
void setPrinterApiKey(String printerApiKey);
String getPrinterHostName();
void setPrinterHostName(String printerHostName);
String getPrinterServer();
void setPrinterServer(String printerServer);
int getPrinterPort();
void setPrinterPort(int printerPort);
String getPrinterAuthUser();
void setPrinterAuthUser(String printerAuthUser);
String getPrinterAuthPass();
void setPrinterAuthPass(String printerAuthPass);
bool hasPrinterPsu();
void setHasPrinterPsu(bool hasPsu);
int getWebserverPort();
bool getWebserverIsBasicAuth();
void setWebserverIsBasicAuth(bool webserverIsBasicAuth);
String getWebserverUsername();
void setWebserverUsername(String webserverUsername);
String getWebserverPassword();
void setWebserverPassword(String webserverPassword);
String getWebserverTheme();
void setWebserverTheme(String webserverTheme);
bool isDisplayInverted();
void setIsDisplayInverted(bool displayInvertDisplay);
int getClockUtcOffset();
void setClockUtcOffset(int clockUtcOffset);
bool getDisplayClock();
void setDisplayClock(bool displayClock);
bool getClockIs24h();
void setClockIs24h(bool clockIs24h);
int getClockResyncMinutes();
void setClockResyncMinutes(int clockResyncMinutes);
bool useLedFlash();
void setUseLedFlash(bool useLedFlash);
bool getWeatherShow();
void setWeatherShow(bool weatherShow);
String getWeatherApiKey();
void setWeatherApiKey(String weatherApiKey);
int getWeatherCityId();
void setWeatherCityId(int weatherCityId);
bool getWeatherIsMetric();
void setWeatherIsMetric(bool weatherIsMetric);
String getWeatherLang();
void setWeatherLang(String weatherLang);
void setDisplayClient(BaseDisplayClient *baseDisplayClient);
void ledOnOff(boolean value);
void flashLED(int number, int delayTime);
bool resetConfig();
void registerPrinterClient(int id, BasePrinterClient *basePrinterClient);
PrinterDataStruct *getPrinterSettings();
PrinterDataStruct *addPrinterSetting();
int getNumPrinters();
String getPrinterStateAsText(PrinterDataStruct *printerHandle);
String getPrinterClientType(PrinterDataStruct *printerHandle);
void syncPrinter(PrinterDataStruct *printerHandle);
private:
void initDefaultConfig();
bool readSettingsForChar(String line, String expSearch, char *targetChar, size_t maxLen);
bool readSettingsForBool(String line, String expSearch, bool *targetBool);
bool readSettingsForInt(String line, String expSearch, int *targetInt);
bool readSettingsForString(String line, String expSearch, String *targetString);
public:
int8_t getWifiQuality();
int numberOfSeconds(int time) { return time % 60UL; }
int numberOfMinutes(int time) { return (time / 60UL) % 60UL; }
int numberOfHours(int time) { return time / 3600UL; }
String zeroPad(int value) { String rtnValue = String(value); if (value < 10) { rtnValue = "0" + rtnValue; } return rtnValue; }
};

View File

@ -0,0 +1,16 @@
#pragma once
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <base64.h>
typedef struct {
bool useLedFlash;
bool invertDisplay;
int webserverPort;
String webserverUsername;
String webserverPassword;
bool hasBasicAuth;
int clockWeatherResyncMinutes;
String version;
String lastError;
} SystemDataStruct;

View File

@ -0,0 +1,12 @@
#pragma once
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <base64.h>
typedef struct {
bool show;
String apiKey;
int cityId;
bool isMetric;
String lang;
} WeatherDataStruct;

View File

@ -10,15 +10,10 @@
#include "Network/TimeClient.h"
#include "Network/OpenWeatherMapClient.h"
#include "Network/JsonRequestClient.h"
#if (PRINTERCLIENT == REPETIER_CLIENT)
#include "Clients/RepetierClient.h"
#elif (PRINTERCLIENT == KLIPPER_CLIENT)
#include "Clients/KlipperClient.h"
#elif (PRINTERCLIENT == DUET_CLIENT)
#include "Clients/DuetClient.h"
#else
#include "Clients/OctoPrintClient.h"
#endif
#include "Clients/RepetierClient.h"
#include "Clients/KlipperClient.h"
#include "Clients/DuetClient.h"
#include "Clients/OctoPrintClient.h"
#ifdef USE_NEXTION_DISPLAY
#include "Display/NextionDisplay.h"
#else
@ -35,16 +30,11 @@ OpenWeatherMapClient weatherClient(WEATHER_APIKEY, WEATHER_CITYID, 1, WEATHER_ME
GlobalDataController globalDataController(&timeClient, &weatherClient, &debugController);
WebServer webServer(&globalDataController, &debugController);
// Construct the correct printer client
#if (PRINTERCLIENT == REPETIER_CLIENT)
//RepetierClient printerClient(&globalDataController);
#elif (PRINTERCLIENT == KLIPPER_CLIENT)
KlipperClient printerClient(&globalDataController, &debugController, &jsonRequestClient);
#elif (PRINTERCLIENT == DUET_CLIENT)
DuetClient printerClient(&globalDataController, &debugController, &jsonRequestClient);
#else
OctoPrintClient printerClient(&globalDataController, &debugController, &jsonRequestClient);
#endif
// Register all printer clients
DuetClient printerClient0(&globalDataController, &debugController, &jsonRequestClient);
KlipperClient printerClient1(&globalDataController, &debugController, &jsonRequestClient);
OctoPrintClient printerClient2(&globalDataController, &debugController, &jsonRequestClient);
RepetierClient printerClient3(&globalDataController, &debugController, &jsonRequestClient);
// Construct correct display client
#ifdef USE_NEXTION_DISPLAY

View File

@ -44,17 +44,17 @@ WiFiClient JsonRequestClient::requestWifiClient(
}
if (requestClient.println() == 0) {
this->debugController->printLn("Connection to " + fullTarget + " failed.");
this->debugController->printLn("SOCKET: Connection to " + fullTarget + " failed.");
this->debugController->printLn("");
this->lastError = "Connection to " + fullTarget + " failed.";
this->lastError = "SOCKET: Connection to " + fullTarget + " failed.";
return requestClient;
}
}
else {
// error message if no client connect
this->debugController->printLn("Connection failed: " + fullTarget);
this->debugController->printLn("SOCKET: Connection failed: " + fullTarget);
this->debugController->printLn("");
this->lastError = "Connection failed: " + fullTarget;
this->lastError = "SOCKET: Connection failed: " + fullTarget;
return requestClient;
}
@ -75,7 +75,7 @@ WiFiClient JsonRequestClient::requestWifiClient(
if (strcmp(status, "HTTP/1.1 200 OK") != 0 && strcmp(status, "HTTP/1.1 409 CONFLICT") != 0 && strcmp(status, "HTTP/1.1 503 Service Unavailable") != 0) {
this->debugController->print("Unexpected response: ");
this->debugController->printLn(status);
this->lastError = "Response: " + String(status);
this->lastError = "SOCKET: Response: " + String(status);
return requestClient;
}
@ -83,7 +83,7 @@ WiFiClient JsonRequestClient::requestWifiClient(
char endOfHeaders[] = "\r\n\r\n";
if (!requestClient.find(endOfHeaders)) {
this->debugController->printLn("Invalid response");
this->lastError = "Invalid response from " + fullTarget;
this->lastError = "SOCKET: Invalid response from " + fullTarget;
}
return requestClient;
@ -112,7 +112,7 @@ DynamicJsonDocument *JsonRequestClient::requestJson(
DeserializationError error = deserializeJson(*returnJson, reqClient);
if (error) {
this->debugController->printLn("Data Parsing failed: " + server + ":" + String(port) + "[" + error.c_str() + "]");
this->lastError = "Data Parsing failed: " + server + ":" + String(port);
this->lastError = "PARSER: Data Parsing failed: " + server + ":" + String(port);
reqClient.stop();
return NULL;
}

View File

@ -18,8 +18,12 @@ bool TimeClient::handleSync(int snycDelayMinutes) {
}
int TimeClient::getMinutesFromLast(long lastEpochToUse) {
int minutes = (this->getCurrentEpoch() - lastEpochToUse) / 60;
return minutes;
return this->getSecondsFromLast(lastEpochToUse) / 60;
}
int TimeClient::getSecondsFromLast(long lastEpochToUse) {
int seconds = (this->getCurrentEpoch() - lastEpochToUse);
return seconds;
}
void TimeClient::resetLastEpoch() {
@ -90,6 +94,14 @@ String TimeClient::getHours() {
return String(hours); // print the hour (86400 equals secs per day)
}
int TimeClient::getMinutesNumber() {
if (localEpoc == 0) {
return 0;
}
return ((getCurrentEpochWithUtcOffset() % 3600) / 60);
}
String TimeClient::getMinutes() {
if (localEpoc == 0) {
return "--";
@ -101,6 +113,14 @@ String TimeClient::getMinutes() {
}
return String(minutes);
}
int TimeClient::getSecondsNumber() {
if (localEpoc == 0) {
return 0;
}
return getCurrentEpochWithUtcOffset() % 60;
}
String TimeClient::getSeconds() {
if (localEpoc == 0) {
return "--";

View File

@ -22,14 +22,19 @@ public:
void updateTime();
bool handleSync(int snycDelayMinutes);
int getMinutesFromLast(long lastEpochToUse);
int getSecondsFromLast(long lastEpochToUse);
void resetLastEpoch();
long getLastEpoch();
void setUtcOffset(float utcOffset);
String getHours();
String getAmPmHours();
String getAmPm();
int getMinutesNumber();
String getMinutes();
int getSecondsNumber();
String getSeconds();
String getFormattedTime();
String getAmPmFormattedTime();

View File

@ -1,47 +1,8 @@
#include "WebServer.h"
String CHANGE_FORM = ""; // moved to config to make it dynamic
static const char CLOCK_FORM[] PROGMEM = "<hr><p><input name='isClockEnabled' class='w3-check w3-margin-top' type='checkbox' %IS_CLOCK_CHECKED%> Display Clock when printer is off</p>"
"<p><input name='is24hour' class='w3-check w3-margin-top' type='checkbox' %IS_24HOUR_CHECKED%> Use 24 Hour Clock (military time)</p>"
"<p><input name='invDisp' class='w3-check w3-margin-top' type='checkbox' %IS_INVDISP_CHECKED%> Flip display orientation</p>"
"<p><input name='useFlash' class='w3-check w3-margin-top' type='checkbox' %USEFLASH%> Flash System LED on Service Calls</p>"
"<p><input name='hasPSU' class='w3-check w3-margin-top' type='checkbox' %HAS_PSU_CHECKED%> Use OctoPrint PSU control plugin for clock/blank</p>"
"<p>Clock Sync / Weather Refresh (minutes) <select class='w3-option w3-padding' name='refresh'>%OPTIONS%</select></p>";
static const char THEME_FORM[] PROGMEM = "<p>Theme Color <select class='w3-option w3-padding' name='theme'>%THEME_OPTIONS%</select></p>"
"<p><label>UTC Time Offset</label><input class='w3-input w3-border w3-margin-bottom' type='text' name='utcoffset' value='%UTCOFFSET%' maxlength='12'></p><hr>"
"<p><input name='isBasicAuth' class='w3-check w3-margin-top' type='checkbox' %IS_BASICAUTH_CHECKED%> Use Security Credentials for Configuration Changes</p>"
"<p><label>User ID (for this interface)</label><input class='w3-input w3-border w3-margin-bottom' type='text' name='userid' value='%USERID%' maxlength='20'></p>"
"<p><label>Password </label><input class='w3-input w3-border w3-margin-bottom' type='password' name='stationpassword' value='%STATIONPASSWORD%'></p>"
"<button class='w3-button w3-block w3-grey w3-section w3-padding' type='submit'>Save</button></form>";
static const char COLOR_THEMES[] PROGMEM = "<option>red</option>"
"<option>pink</option>"
"<option>purple</option>"
"<option>deep-purple</option>"
"<option>indigo</option>"
"<option>blue</option>"
"<option>light-blue</option>"
"<option>cyan</option>"
"<option>teal</option>"
"<option>green</option>"
"<option>light-green</option>"
"<option>lime</option>"
"<option>khaki</option>"
"<option>yellow</option>"
"<option>amber</option>"
"<option>orange</option>"
"<option>deep-orange</option>"
"<option>blue-grey</option>"
"<option>brown</option>"
"<option>grey</option>"
"<option>dark-grey</option>"
"<option>black</option>"
"<option>w3schools</option>";
WebServer::WebServer(GlobalDataController *globalDataController, DebugController *debugController) {
this->globalDataController = globalDataController;
this->debugController = debugController;
@ -50,21 +11,32 @@ WebServer::WebServer(GlobalDataController *globalDataController, DebugController
void WebServer::setup() {
static WebServer* obj = this;
this->server = new ESP8266WebServer(this->globalDataController->getWebserverPort());
this->server = new ESP8266WebServer(this->globalDataController->getSystemSettings()->webserverPort);
this->serverUpdater = new ESP8266HTTPUpdateServer();
this->server->on("/", []() { obj->displayPrinterStatus(); });
this->server->on("/systemreset", []() { obj->handleSystemReset(); });
this->server->on("/forgetwifi", []() { obj->handleWifiReset(); });
this->server->on("/configurestation", []() { obj->handleConfigureStation(); });
this->server->on("/configureprinter", []() { obj->handleConfigurePrinter(); });
this->server->on("/configureweather", []() { obj->handleWeatherConfigure(); });
this->server->on("/updateconfig", []() { obj->handleUpdateConfig(); });
this->server->on("/updatestationconfig", []() { obj->handleUpdateStation(); });
this->server->on("/updateweatherconfig", []() { obj->handleUpdateWeather(); });
this->server->on("/configurestation/show", []() { obj->handleConfigureStation(); });
this->server->on("/configurestation/update", []() { obj->handleUpdateStation(); });
this->server->on("/configureprinter/show", []() { obj->handleConfigurePrinter(); });
this->server->on("/configureprinter/edit", []() { obj->handleUpdatePrinter(); });
this->server->on("/configureprinter/delete", []() { obj->handleConfigurePrinter(); });
this->server->on("/configureweather/show", []() { obj->handleConfigureWeather(); });
this->server->on("/configureweather/update", []() { obj->handleUpdateWeather(); });
this->server->on("/configuresensor/show", []() { obj->handleConfigureSensor(); });
this->server->on("/configuresensor/update", []() { obj->handleConfigureSensor(); });
this->server->on("/update", HTTP_GET, []() { obj->handleUpdatePage(); });
this->server->on("/updateconfig", []() { obj->handleUpdateConfig(); });
this->server->onNotFound([]() { obj->redirectHome(); });
this->serverUpdater->setup(this->server, "/update", this->globalDataController->getWebserverUsername(), this->globalDataController->getWebserverPassword());
this->serverUpdater->setup(
this->server,
"/update",
this->globalDataController->getSystemSettings()->webserverUsername,
this->globalDataController->getSystemSettings()->webserverPassword
);
// Start the server
@ -76,21 +48,9 @@ void WebServer::handleClient() {
this->server->handleClient();
}
boolean WebServer::authentication() {
if (this->globalDataController->getWebserverIsBasicAuth() &&
(this->globalDataController->getWebserverUsername().length() >= 1 && this->globalDataController->getWebserverPassword().length() >= 1)
) {
return this->server->authenticate(
this->globalDataController->getWebserverUsername().c_str(),
this->globalDataController->getWebserverPassword().c_str()
);
}
return true; // Authentication not required
}
void WebServer::redirectHome() {
void WebServer::redirectTarget(String targetUri) {
// Send them back to the Root Directory
this->server->sendHeader("Location", String("/"), true);
this->server->sendHeader("Location", targetUri, true);
this->server->sendHeader("Cache-Control", "no-cache, no-store");
this->server->sendHeader("Pragma", "no-cache");
this->server->sendHeader("Expires", "-1");
@ -98,18 +58,25 @@ void WebServer::redirectHome() {
this->server->client().stop();
}
void WebServer::redirectHome() {
this->redirectTarget("/");
}
void WebServer::displayPrinterStatus() {
BasePrinterClient *printerClient = this->globalDataController->getPrinterClient();
WebserverMemoryVariables::sendHeader(this->server, this->globalDataController, "Status", "Monitor", true);
/*BasePrinterClient *printerClient = this->globalDataController->getPrinterClient();
String html = "";
WebserverMemoryVariables::sendHeader(this->server, this->globalDataController, "Status", "Monitor", true);
String displayTime =
this->globalDataController->getTimeClient()->getAmPmHours() + ":" +
this->globalDataController->getTimeClient()->getMinutes() + ":" +
this->globalDataController->getTimeClient()->getSeconds() + " " +
this->globalDataController->getTimeClient()->getAmPm();
if (this->globalDataController->getClockIs24h()) {
if (this->globalDataController->getClockSettings()->is24h) {
displayTime =
this->globalDataController->getTimeClient()->getHours() + ":" +
this->globalDataController->getTimeClient()->getMinutes() + ":" +
@ -181,7 +148,7 @@ void WebServer::displayPrinterStatus() {
this->server->sendContent(html); // spit out what we got
html = "";
if (this->globalDataController->getWeatherShow()) {
if (this->globalDataController->getWeatherSettings()->show) {
OpenWeatherMapClient *weatherClient = this->globalDataController->getWeatherClient();
if (weatherClient->getCity(0) == "") {
html += "<p>Please <a href='/configureweather'>Configure Weather</a> API</p>";
@ -204,7 +171,7 @@ void WebServer::displayPrinterStatus() {
this->server->sendContent(html); // spit out what we got
html = ""; // fresh start
}
}*/
WebserverMemoryVariables::sendFooter(this->server, this->globalDataController);
}
@ -212,7 +179,7 @@ void WebServer::displayPrinterStatus() {
void WebServer::handleUpdateConfig() {
boolean flipOld = this->globalDataController->isDisplayInverted();
/*boolean flipOld = this->globalDataController->isDisplayInverted();
if (!this->authentication()) {
return this->server->requestAuthentication();
}
@ -239,7 +206,7 @@ void WebServer::handleUpdateConfig() {
this->globalDataController->setWebserverUsername(temp);
temp = this->server->arg("stationpassword");
this->globalDataController->setWebserverPassword(temp);
this->globalDataController->setUseLedFlash(this->server->hasArg("useFlash"));
//this->globalDataController->setUseLedFlash(this->server->hasArg("useFlash"));
this->globalDataController->writeSettings();
this->findMDNS();
@ -250,12 +217,14 @@ void WebServer::handleUpdateConfig() {
this->globalDataController->getDisplayClient()->flipDisplayUpdate();
}
this->globalDataController->getDisplayClient()->handleUpdate();
this->globalDataController->getTimeClient()->resetLastEpoch();
this->globalDataController->getTimeClient()->resetLastEpoch();*/
this->redirectHome();
}
void WebServer::findMDNS() {
if (this->globalDataController->getPrinterHostName() == "" || ENABLE_OTA == false) {
return; // nothing to do here
/*if (this->globalDataController->getPrinterHostName() == "" || ENABLE_OTA == false) {
return; // nothing to do here
}
// We now query our network for 'web servers' service
@ -282,7 +251,7 @@ void WebServer::findMDNS() {
);
this->globalDataController->writeSettings(); // update the settings
}
}
}*/
}
/*
@ -406,11 +375,14 @@ void WebServer::handleConfigure() {
void WebServer::handleConfigurePrinter() {
void WebServer::handleConfigureSensor() {
if (!this->authentication()) {
return this->server->requestAuthentication();
}
WebserverMemoryVariables::sendHeader(this->server, this->globalDataController, "Configure", "Printers");
WebserverMemoryVariables::sendHeader(this->server, this->globalDataController, "Configure", "Sensor");
WebserverMemoryVariables::sendFooter(this->server, this->globalDataController);
}
@ -427,8 +399,79 @@ void WebServer::handleConfigurePrinter() {
/**
* @brief Handle authentification on all subsites
* @return boolean
*/
boolean WebServer::authentication() {
SystemDataStruct *systemData = this->globalDataController->getSystemSettings();
if (systemData->hasBasicAuth && (systemData->webserverUsername.length() >= 1 && systemData->webserverPassword.length() >= 1)
) {
return this->server->authenticate(systemData->webserverUsername.c_str(), systemData->webserverPassword.c_str());
}
return true; // Authentication not required
}
/**
* @brief Send printer configuration page to client
*/
void WebServer::handleConfigurePrinter() {
if (!this->authentication()) {
return this->server->requestAuthentication();
}
WebserverMemoryVariables::sendHeader(this->server, this->globalDataController, "Configure", "Printers");
WebserverMemoryVariables::sendPrinterConfigForm(this->server, this->globalDataController);
WebserverMemoryVariables::sendFooter(this->server, this->globalDataController);
}
/**
* @brief Update configuration for Printer
*/
void WebServer::handleUpdatePrinter() {
if (!this->authentication()) {
return this->server->requestAuthentication();
}
PrinterDataStruct *targetPrinter = NULL;
int targetPrinterId = this->server->arg("id").toInt() - 1;
if (targetPrinterId >= 0) {
PrinterDataStruct *existPrinters = this->globalDataController->getPrinterSettings();
for(int i=0; i<this->globalDataController->getNumPrinters(); i++) {
if (i == targetPrinterId) {
targetPrinter = &(existPrinters[i]);
break;
}
}
} else {
targetPrinter = this->globalDataController->addPrinterSetting();
}
if (targetPrinter == NULL) {
this->globalDataController->getSystemSettings()->lastError = FPSTR(ERROR_MESSAGES_ERR1);
this->redirectTarget("/configureprinter/show");
return;
}
// Set data
MemoryHelper::stringToChar(this->server->arg("e-tname"), targetPrinter->customName, 20);
targetPrinter->apiType = this->server->arg("e-tapi").toInt();
MemoryHelper::stringToChar("", targetPrinter->apiKey, 60);
MemoryHelper::stringToChar(this->server->arg("e-taddr"), targetPrinter->remoteAddress, 60);
targetPrinter->remotePort = this->server->arg("e-tport").toInt();
targetPrinter->hasPsuControl = this->server->hasArg("e-tpsu");
targetPrinter->basicAuthNeeded = this->server->hasArg("e-tapipw");
MemoryHelper::stringToChar(this->server->arg("e-tapiuser"), targetPrinter->basicAuthUsername, 30);
MemoryHelper::stringToChar(this->server->arg("e-tapipass"), targetPrinter->basicAuthPassword, 60);
//http://192.168.0.239/configureprinter/show?id=0&e-tname=asdasd&e-tapi=Klipper&e-taddr=123.213.123.121&e-tport=80&e-tapipw=on&e-tapiuser=admin&e-tapipass=admin
this->globalDataController->getSystemSettings()->lastError = FPSTR(ERROR_MESSAGES_ERR1);
this->globalDataController->writeSettings();
this->redirectTarget("/configureprinter/show");
}
@ -449,27 +492,30 @@ void WebServer::handleConfigureStation() {
* @brief Update configuration for station
*/
void WebServer::handleUpdateStation() {
boolean flipOld = this->globalDataController->isDisplayInverted();
if (!this->authentication()) {
return this->server->requestAuthentication();
}
SystemDataStruct *systemSettings = this->globalDataController->getSystemSettings();
ClockDataStruct *clockSettings = this->globalDataController->getClockSettings();
boolean flipOld = systemSettings->invertDisplay;
this->globalDataController->setDisplayClock(this->server->hasArg("isClockEnabled"));
this->globalDataController->setIsDisplayInverted(this->server->hasArg("invDisp"));
this->globalDataController->setUseLedFlash(this->server->hasArg("useFlash"));
this->globalDataController->setClockIs24h(this->server->hasArg("is24hour"));
this->globalDataController->setClockResyncMinutes(this->server->arg("refresh").toInt());
this->globalDataController->setClockUtcOffset(this->server->arg("utcoffset").toFloat());
this->globalDataController->setWebserverIsBasicAuth(this->server->hasArg("isBasicAuth"));
String temp = this->server->arg("userid");
this->globalDataController->setWebserverUsername(temp);
temp = this->server->arg("stationpassword");
this->globalDataController->setWebserverPassword(temp);
clockSettings->show = this->server->hasArg("isClockEnabled");
clockSettings->is24h = this->server->hasArg("is24hour");
clockSettings->utcOffset = this->server->arg("utcoffset").toInt();
systemSettings->clockWeatherResyncMinutes = this->server->arg("refresh").toInt();
systemSettings->hasBasicAuth = this->server->hasArg("isBasicAuth");
systemSettings->invertDisplay = this->server->hasArg("invDisp");
systemSettings->useLedFlash = this->server->hasArg("useFlash");
systemSettings->webserverPassword = this->server->arg("stationpassword");
systemSettings->webserverUsername = this->server->arg("userid");
this->globalDataController->writeSettings();
this->findMDNS();
if (this->globalDataController->isDisplayInverted() != flipOld) {
if (systemSettings->invertDisplay != flipOld) {
this->globalDataController->getDisplayClient()->flipDisplayUpdate();
}
this->globalDataController->getDisplayClient()->handleUpdate();
this->globalDataController->getTimeClient()->resetLastEpoch();
this->redirectHome();
@ -478,7 +524,7 @@ void WebServer::handleUpdateStation() {
/**
* @brief Send weather configuration page to client
*/
void WebServer::handleWeatherConfigure() {
void WebServer::handleConfigureWeather() {
if (!this->authentication()) {
return this->server->requestAuthentication();
}
@ -494,11 +540,13 @@ void WebServer::handleUpdateWeather() {
if (!this->authentication()) {
return this->server->requestAuthentication();
}
this->globalDataController->setWeatherShow(this->server->hasArg("isWeatherEnabled"));
this->globalDataController->setWeatherApiKey(this->server->arg("openWeatherMapApiKey"));
this->globalDataController->setWeatherCityId(this->server->arg("city1").toInt());
this->globalDataController->setWeatherIsMetric(this->server->hasArg("metric"));
this->globalDataController->setWeatherLang(this->server->arg("language"));
WeatherDataStruct *weatherSettings = this->globalDataController->getWeatherSettings();
weatherSettings->show = this->server->hasArg("isWeatherEnabled");
weatherSettings->apiKey = this->server->arg("openWeatherMapApiKey");
weatherSettings->cityId = this->server->arg("city1").toInt();
weatherSettings->isMetric = this->server->hasArg("metric");
weatherSettings->lang = this->server->arg("language");
this->globalDataController->writeSettings();
this->globalDataController->getDisplayClient()->handleUpdate();

View File

@ -6,6 +6,7 @@
#include <ESP8266mDNS.h>
#include "../Global/GlobalDataController.h"
#include "WebserverMemoryVariables.h"
#include "../../include/MemoryHelper.h"
class WebServer {
private:
@ -22,14 +23,19 @@ public:
void handleClient();
boolean authentication();
void redirectHome();
void redirectTarget(String targetUri);
void displayPrinterStatus();
void handleSystemReset();
void handleWifiReset();
void handleUpdateConfig();
void handleUpdateStation();
void handleUpdateWeather();
void handleConfigurePrinter();
void handleUpdatePrinter();
void handleConfigureStation();
void handleWeatherConfigure();
void handleUpdateStation();
void handleConfigureWeather();
void handleUpdateWeather();
void handleConfigureSensor();
void handleUpdatePage();
};

View File

@ -25,7 +25,7 @@ void WebserverMemoryVariables::sendHeader(
boolean refresh
) {
globalDataController->ledOnOff(true);
int8_t rssi = globalDataController->getWifiQuality();
int8_t rssi = EspController::getWifiQuality();
server->sendHeader("Cache-Control", "no-cache, no-store");
server->sendHeader("Pragma", "no-cache");
@ -38,7 +38,7 @@ void WebserverMemoryVariables::sendHeader(
server->sendContent("<meta http-equiv=\"refresh\" content=\"30\">");
}
server->sendContent(String(FPSTR(HEADER_BLOCK2)));
server->sendContent("<span class='bx--header__name--prefix'>PrintBuddy&nbsp;</span>V" + String(VERSION));
server->sendContent("<span class='bx--header__name--prefix'>PrintBuddy&nbsp;</span>V" + String(globalDataController->getSystemSettings()->version));
server->sendContent(String(FPSTR(HEADER_BLOCK3)));
server->sendContent(String(FPSTR(MENUE_ITEMS)));
server->sendContent(String(FPSTR(HEADER_BLOCK4)));
@ -46,17 +46,23 @@ void WebserverMemoryVariables::sendHeader(
uint32_t heapFree = 0;
uint16_t heapMax = 0;
uint8_t heapFrag = 0;
ESP.getHeapStats(&heapFree, &heapMax, &heapFrag);
EspController::getHeap(&heapFree, &heapMax, &heapFrag);
server->sendContent("<div>WiFi Signal Strength: " + String(rssi) + "%</div>");
server->sendContent("<div>ESP ChipID: " + String(ESP.getChipId()) + "</div>");
server->sendContent("<div>ESP CoreVersion: " + String(ESP.getCoreVersion()) + "</div>");
server->sendContent("<div>Heap (frag/free/max): " + String(heapFrag) + "|" + String(heapFree) + "|" + String(heapMax) + "</div>");
server->sendContent("<div>Heap (frag/free/max): " + String(heapFrag) + "% |" + String(heapFree) + " b|" + String(heapMax) + " b</div>");
server->sendContent(String(FPSTR(HEADER_BLOCK5)));
server->sendContent(pageLabel);
server->sendContent("</h4><h1 id='page-title' class='page-header__title'>");
server->sendContent(pageTitle);
server->sendContent("</h1></div>");
if (globalDataController->getSystemSettings()->lastError.length() > 0) {
String errorBlock = FPSTR(HEADER_BLOCK_ERROR);
errorBlock.replace("%ERRORMSG%", globalDataController->getSystemSettings()->lastError);
server->sendContent(errorBlock);
}
}
/**
@ -85,35 +91,36 @@ void WebserverMemoryVariables::sendUpdateForm(ESP8266WebServer *server, GlobalDa
* @param server Send out instancce
* @param globalDataController Access to global data
*/
void WebserverMemoryVariables::sendWeatherConfigForm(ESP8266WebServer *server, GlobalDataController *globalDataController) {
String isWeatherChecked = "";
String isMetricChecked = "";
if (globalDataController->getWeatherShow()) {
isWeatherChecked = "checked='checked'";
}
if (globalDataController->getWeatherIsMetric()) {
isMetricChecked = "checked='checked'";
}
void WebserverMemoryVariables::sendWeatherConfigForm(ESP8266WebServer *server, GlobalDataController *globalDataController) {
server->sendContent(FPSTR(WEATHER_FORM_START));
WebserverMemoryVariables::sendFormCheckbox(
server,
FPSTR(WEATHER_FORM1_ID),
globalDataController->getWeatherSettings()->show,
FPSTR(WEATHER_FORM1_LABEL)
);
WebserverMemoryVariables::sendFormCheckbox(
server,
FPSTR(WEATHER_FORM2_ID),
globalDataController->getWeatherSettings()->isMetric,
FPSTR(WEATHER_FORM2_LABEL_ON),
FPSTR(WEATHER_FORM2_LABEL_OFF)
);
String form = FPSTR(WEATHER_FORM1);
form.replace("%IS_WEATHER_CHECKED%", isWeatherChecked);
server->sendContent(form);
form = FPSTR(WEATHER_FORM2);
form.replace("%METRIC%", isMetricChecked);
server->sendContent(form);
form = FPSTR(WEATHER_FORM3);
form.replace("%WEATHERKEY%", globalDataController->getWeatherApiKey());
String form = FPSTR(WEATHER_FORM3);
form.replace("%WEATHERKEY%", globalDataController->getWeatherSettings()->apiKey);
server->sendContent(form);
form = FPSTR(WEATHER_FORM4);
form.replace("%CITY1%", String(globalDataController->getWeatherCityId()));
form.replace("%CITY1%", String(globalDataController->getWeatherSettings()->cityId));
form.replace("%CITYNAME1%", globalDataController->getWeatherClient()->getCity(0));
server->sendContent(form);
form = FPSTR(WEATHER_FORM_OPTIONS);
form.replace(">"+String(globalDataController->getWeatherLang())+"<", " selected>"+String(globalDataController->getWeatherLang())+"<");
form.replace(
">"+String(globalDataController->getWeatherSettings()->lang)+"<",
" selected>"+String(globalDataController->getWeatherSettings()->lang)+"<"
);
server->sendContent(form);
form = FPSTR(WEATHER_FORM5);
@ -126,59 +133,211 @@ void WebserverMemoryVariables::sendWeatherConfigForm(ESP8266WebServer *server, G
* @param globalDataController Access to global data
*/
void WebserverMemoryVariables::sendStationConfigForm(ESP8266WebServer *server, GlobalDataController *globalDataController) {
String isClockChecked = "";
String is24hourChecked = "";
String isInvDisp = "";
String isFlashLED = "";
String isUseSecurityChecked = "";
if (globalDataController->isDisplayInverted()) {
isInvDisp = "checked='checked'";
}
if (globalDataController->useLedFlash()) {
isFlashLED = "checked='checked'";
}
if (globalDataController->getDisplayClock()) {
isClockChecked = "checked='checked'";
}
if (globalDataController->getClockIs24h()) {
is24hourChecked = "checked='checked'";
}
if (globalDataController->getWebserverIsBasicAuth()) {
isUseSecurityChecked = "checked='checked'";
}
server->sendContent(FPSTR(STATION_CONFIG_FORM_START));
WebserverMemoryVariables::sendFormCheckbox(
server,
FPSTR(STATION_CONFIG_FORM1_ID),
globalDataController->getClockSettings()->show,
FPSTR(STATION_CONFIG_FORM1_LABEL)
);
WebserverMemoryVariables::sendFormCheckbox(
server,
FPSTR(STATION_CONFIG_FORM2_ID),
globalDataController->getClockSettings()->is24h,
FPSTR(STATION_CONFIG_FORM2_LABEL)
);
WebserverMemoryVariables::sendFormCheckbox(
server,
FPSTR(STATION_CONFIG_FORM3_ID),
globalDataController->getSystemSettings()->invertDisplay,
FPSTR(STATION_CONFIG_FORM3_LABEL)
);
WebserverMemoryVariables::sendFormCheckbox(
server,
FPSTR(STATION_CONFIG_FORM4_ID),
globalDataController->getSystemSettings()->useLedFlash,
FPSTR(STATION_CONFIG_FORM4_LABEL)
);
String form = FPSTR(STATION_CONFIG_FORM1);
form.replace("%IS_CLOCK_CHECKED%", isClockChecked);
server->sendContent(form);
form = FPSTR(STATION_CONFIG_FORM2);
form.replace("%IS_24HOUR_CHECKED%", is24hourChecked);
server->sendContent(form);
form = FPSTR(STATION_CONFIG_FORM3);
form.replace("%IS_INVDISP_CHECKED%", isInvDisp);
server->sendContent(form);
form = FPSTR(STATION_CONFIG_FORM4);
form.replace("%USEFLASH%", isFlashLED);
server->sendContent(form);
form = FPSTR(STATION_CONFIG_FORM5);
String form = FPSTR(STATION_CONFIG_FORM5);
String options = FPSTR(STATION_CONFIG_FORM5OPT);
options.replace(">"+String(globalDataController->getClockResyncMinutes())+"<", " selected>"+String(globalDataController->getClockResyncMinutes())+"<");
options.replace(
">"+String(globalDataController->getSystemSettings()->clockWeatherResyncMinutes)+"<",
" selected>"+String(globalDataController->getSystemSettings()->clockWeatherResyncMinutes)+"<"
);
form.replace("%OPTIONS%", options);
server->sendContent(form);
form = FPSTR(STATION_CONFIG_FORM6);
form.replace("%UTCOFFSET%", String(globalDataController->getClockUtcOffset()));
form.replace("%UTCOFFSET%", String(globalDataController->getClockSettings()->utcOffset));
server->sendContent(form);
form = FPSTR(STATION_CONFIG_FORM7);
form.replace("%IS_BASICAUTH_CHECKED%", isUseSecurityChecked);
server->sendContent(form);
WebserverMemoryVariables::sendFormCheckboxEvent(
server,
FPSTR(STATION_CONFIG_FORM7_ID),
globalDataController->getSystemSettings()->hasBasicAuth,
FPSTR(STATION_CONFIG_FORM7_LABEL),
"showhide(this, 'uspw')"
);
form = FPSTR(STATION_CONFIG_FORM8);
form.replace("%USERID%", globalDataController->getWebserverUsername());
form.replace("%STATIONPASSWORD%", globalDataController->getWebserverPassword());
form.replace("%USERID%", globalDataController->getSystemSettings()->webserverUsername);
form.replace("%STATIONPASSWORD%", globalDataController->getSystemSettings()->webserverPassword);
server->sendContent(form);
}
/**
* @brief Send out configuration for printer
* @param server Send out instancce
* @param globalDataController Access to global data
*/
void WebserverMemoryVariables::sendPrinterConfigForm(ESP8266WebServer *server, GlobalDataController *globalDataController) {
server->sendContent(FPSTR(CONFPRINTER_FORM_START));
int totalPrinters = globalDataController->getNumPrinters();
PrinterDataStruct *printerConfigs = globalDataController->getPrinterSettings();
for(int i=0; i<totalPrinters; i++) {
String printerEntryRow = FPSTR(CONFPRINTER_FORM_ROW);
printerEntryRow.replace("%ID%", String(i+1));
printerEntryRow.replace("%NAME%", String(printerConfigs[i].customName));
printerEntryRow.replace("%TYPE%", globalDataController->getPrinterClientType(&printerConfigs[i]));
String state = FPSTR(CONFPRINTER_FORM_ROW_OK);
if ((printerConfigs[i].state == PRINTER_STATE_OFFLINE) || (printerConfigs[i].state == PRINTER_STATE_ERROR)) {
state = FPSTR(CONFPRINTER_FORM_ROW_ERROR);
}
state.replace("%STATUS%", globalDataController->getPrinterStateAsText(&printerConfigs[i]));
printerEntryRow.replace("%STATE%", state);
server->sendContent(printerEntryRow);
}
// Generate all modals
for(int i=0; i<totalPrinters; i++) {
WebserverMemoryVariables::sendPrinterConfigFormAEModal(server, i + 1, &printerConfigs[i]);
}
WebserverMemoryVariables::sendPrinterConfigFormAEModal(server, 0, NULL);
/*static const char CONFPRINTER_FORM_ROW_OFFLINE[] PROGMEM = "<div class='bx--tag bx--tag--magenta'>"
"Offline"
"</div>";
static const char CONFPRINTER_FORM_ROW_ONLINE[] PROGMEM = "<div class='bx--tag bx--tag--green'>"
"Online"
"</div>";
*/
server->sendContent(FPSTR(CONFPRINTER_FORM_END));
}
void WebserverMemoryVariables::sendPrinterConfigFormAEModal(ESP8266WebServer *server, int id, PrinterDataStruct *forPrinter) {
String printerEditModal = FPSTR(CONFPRINTER_FORM_ADDEDIT1);
printerEditModal.replace("%ID%", String(id));
if (id == 0) {
printerEditModal.replace("%TITLE%", FPSTR(CONFPRINTER_FORM_ADDEDIT_TA));
} else {
printerEditModal.replace("%TITLE%", FPSTR(CONFPRINTER_FORM_ADDEDIT_TE));
}
if (forPrinter == NULL) {
printerEditModal.replace("%NAME%", "");
printerEditModal.replace("%TARGETADDR%", "");
printerEditModal.replace("%TARGETPORT%", "80");
} else {
printerEditModal.replace("%NAME%", String(forPrinter->customName));
printerEditModal.replace("%TARGETADDR%", String(forPrinter->remoteAddress));
printerEditModal.replace("%TARGETPORT%", String(forPrinter->remotePort));
}
server->sendContent(printerEditModal);
}
/**
* @brief Send out an single checkbox form row
* @param server Send out instancce
* @param formId Form id/name
* @param isChecked Checkbox checked
* @param label Text for activated/deactivated
*/
void WebserverMemoryVariables::sendFormCheckbox(ESP8266WebServer *server, String formId, bool isChecked, String label) {
WebserverMemoryVariables::sendFormCheckboxEvent(server, formId, isChecked, label, "");
}
/**
* @brief Send out an single checkbox form row
* @param server Send out instancce
* @param formId Form id/name
* @param isChecked Checkbox checked
* @param labelOn Text for activated
* @param labelOff Text for deactivated
*/
void WebserverMemoryVariables::sendFormCheckbox(ESP8266WebServer *server, String formId, bool isChecked, String labelOn, String labelOff) {
WebserverMemoryVariables::sendFormCheckboxEvent(server, formId, isChecked, labelOn, labelOff, "");
}
/**
* @brief Send out an single checkbox form row with onChangeEvent
* @param server Send out instancce
* @param formId Form id/name
* @param isChecked Checkbox checked
* @param label Text for activated/deactivated
* @param onChange Javascript function
*/
void WebserverMemoryVariables::sendFormCheckboxEvent(ESP8266WebServer *server, String formId, bool isChecked, String label, String onChange) {
String onAdd = FPSTR(FORM_ITEM_CHECKBOX_ON);
String offAdd = FPSTR(FORM_ITEM_CHECKBOX_OFF);
WebserverMemoryVariables::sendFormCheckboxEvent(server, formId, isChecked, label + onAdd, label + offAdd, onChange);
}
/**
* @brief Send out an single checkbox form row with onChangeEvent
* @param server Send out instancce
* @param formId Form id/name
* @param isChecked Checkbox checked
* @param labelOn Text for activated
* @param labelOff Text for deactivated
* @param onChange Javascript function
*/
void WebserverMemoryVariables::sendFormCheckboxEvent(ESP8266WebServer *server, String formId, bool isChecked, String labelOn, String labelOff, String onChange) {
String isCheckedText = "";
String onChangeText = "";
if (isChecked) {
isCheckedText = "checked='checked'";
}
if (onChange.length() > 0) {
onChangeText = "onchange=\"" + onChange + "\"";
}
String form = FPSTR(FORM_ITEM_CHECKBOX);
form.replace("%FORMID%", formId);
form.replace("%CHECKED%", isCheckedText);
form.replace("%LABELON%", labelOn);
form.replace("%LABELOFF%", labelOff);
form.replace("%ONCHANGE%", onChangeText);
server->sendContent(form);
}

View File

@ -4,18 +4,66 @@
#include <ESP8266WebServer.h>
#include "../Global/GlobalDataController.h"
/**
* Webpage form items for reuse
*/
static const char FORM_ITEM_CHECKBOX[] PROGMEM = "<div class='bx--row'>"
"<div class='bx--col bx--col--auto bx--form-item'>"
"<input class='bx--toggle-input bx--toggle-input--small' id='%FORMID%' type='checkbox' name='%FORMID%' %CHECKED% %ONCHANGE%>"
"<label class='bx--toggle-input__label' for='%FORMID%'>"
"<span class='bx--toggle__switch'>"
"<svg class='bx--toggle__check' width='6px' height='5px' viewBox='0 0 6 5'>"
"<path d='M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z' />"
"</svg>"
"<span class='bx--toggle__text--off' aria-hidden='true'>%LABELOFF%</span>"
"<span class='bx--toggle__text--on' aria-hidden='true'>%LABELON%</span>"
"</span>"
"</label>"
"</div>"
"</div>";
static const char FORM_ITEM_CHECKBOX_ON[] PROGMEM = " activated";
static const char FORM_ITEM_CHECKBOX_OFF[] PROGMEM = " deactivated";
/**
* Webpage side menu right for main items
*/
static const char MENUE_ITEMS[] PROGMEM =
"<li class='cv-switcher-item bx--switcher__item'><a class='cv-switcher-item-link bx--switcher__item-link' href='/'><i class='fa fa-home'></i> Home</a></li>"
"<li class='cv-switcher-item bx--switcher__item'><a class='cv-switcher-item-link bx--switcher__item-link' href='/configureprinter'><i class='fas fa-print'></i></i> Configure Printers</a></li>"
"<li class='cv-switcher-item bx--switcher__item'><a class='cv-switcher-item-link bx--switcher__item-link' href='/configurestation'><i class='fa fa-cog'></i> Configure Station</a></li>"
"<li class='cv-switcher-item bx--switcher__item'><a class='cv-switcher-item-link bx--switcher__item-link' href='/configureweather'><i class='fa fa-cloud'></i> Weather</a></li>"
"<li class='cv-switcher-item bx--switcher__item'><a class='cv-switcher-item-link bx--switcher__item-link' href='/systemreset' onclick='return confirm(\"Do you want to reset to default settings?\")'><i class='fa fa-undo'></i> Reset Settings</a></li>"
"<li class='cv-switcher-item bx--switcher__item'><a class='cv-switcher-item-link bx--switcher__item-link' href='/forgetwifi' onclick='return confirm(\"Do you want to forget to WiFi connection?\")'><i class='fa fa-wifi'></i> Forget WiFi</a></li>"
"<li class='cv-switcher-item bx--switcher__item'><a class='cv-switcher-item-link bx--switcher__item-link' href='/update'><i class='fa fa-wrench'></i> Firmware Update</a></li>"
"<li class='cv-switcher-item bx--switcher__item'><a class='cv-switcher-item-link bx--switcher__item-link' href='https://github.com/Qrome' target='_blank'><i class='fa fa-question-circle'></i> About</a></li>";
"<li class='cv-switcher-item bx--switcher__item'><a class='cv-switcher-item-link bx--switcher__item-link menitem' href='/'>"
"Home"
"<svg focusable='false' preserveAspectRatio='xMidYMid meet' xmlns='http://www.w3.org/2000/svg' fill='currentColor' width='16' height='16' viewBox='0 0 32 32' aria-hidden='true'><path d='M16.6123,2.2138a1.01,1.01,0,0,0-1.2427,0L1,13.4194l1.2427,1.5717L4,13.6209V26a2.0041,2.0041,0,0,0,2,2H26a2.0037,2.0037,0,0,0,2-2V13.63L29.7573,15,31,13.4282ZM18,26H14V18h4Zm2,0V18a2.0023,2.0023,0,0,0-2-2H14a2.002,2.002,0,0,0-2,2v8H6V12.0615l10-7.79,10,7.8005V26Z'></path></svg>"
"</a></li>"
"<li class='cv-switcher-item bx--switcher__item'><a class='cv-switcher-item-link bx--switcher__item-link menitem' href='/configureprinter/show'>"
"Configure Printers"
"<svg focusable='false' preserveAspectRatio='xMidYMid meet' xmlns='http://www.w3.org/2000/svg' fill='currentColor' width='16' height='16' viewBox='0 0 32 32' aria-hidden='true'><path d='M28,9H25V3H7V9H4a2,2,0,0,0-2,2V21a2,2,0,0,0,2,2H7v6H25V23h3a2,2,0,0,0,2-2V11A2,2,0,0,0,28,9ZM9,5H23V9H9ZM23,27H9V17H23Zm5-6H25V15H7v6H4V11H28Z'></path></svg>"
"</a></li>"
"<li class='cv-switcher-item bx--switcher__item'><a class='cv-switcher-item-link bx--switcher__item-link menitem' href='/configurestation/show'>"
"Configure Station"
"<svg focusable='false' preserveAspectRatio='xMidYMid meet' xmlns='http://www.w3.org/2000/svg' fill='currentColor' width='16' height='16' viewBox='0 0 32 32' aria-hidden='true'><path d='M27,16.76c0-.25,0-.5,0-.76s0-.51,0-.77l1.92-1.68A2,2,0,0,0,29.3,11L26.94,7a2,2,0,0,0-1.73-1,2,2,0,0,0-.64.1l-2.43.82a11.35,11.35,0,0,0-1.31-.75l-.51-2.52a2,2,0,0,0-2-1.61H13.64a2,2,0,0,0-2,1.61l-.51,2.52a11.48,11.48,0,0,0-1.32.75L7.43,6.06A2,2,0,0,0,6.79,6,2,2,0,0,0,5.06,7L2.7,11a2,2,0,0,0,.41,2.51L5,15.24c0,.25,0,.5,0,.76s0,.51,0,.77L3.11,18.45A2,2,0,0,0,2.7,21L5.06,25a2,2,0,0,0,1.73,1,2,2,0,0,0,.64-.1l2.43-.82a11.35,11.35,0,0,0,1.31.75l.51,2.52a2,2,0,0,0,2,1.61h4.72a2,2,0,0,0,2-1.61l.51-2.52a11.48,11.48,0,0,0,1.32-.75l2.42.82a2,2,0,0,0,.64.1,2,2,0,0,0,1.73-1L29.3,21a2,2,0,0,0-.41-2.51ZM25.21,24l-3.43-1.16a8.86,8.86,0,0,1-2.71,1.57L18.36,28H13.64l-.71-3.55a9.36,9.36,0,0,1-2.7-1.57L6.79,24,4.43,20l2.72-2.4a8.9,8.9,0,0,1,0-3.13L4.43,12,6.79,8l3.43,1.16a8.86,8.86,0,0,1,2.71-1.57L13.64,4h4.72l.71,3.55a9.36,9.36,0,0,1,2.7,1.57L25.21,8,27.57,12l-2.72,2.4a8.9,8.9,0,0,1,0,3.13L27.57,20Z'></path><path d='M16,22a6,6,0,1,1,6-6A5.94,5.94,0,0,1,16,22Zm0-10a3.91,3.91,0,0,0-4,4,3.91,3.91,0,0,0,4,4,3.91,3.91,0,0,0,4-4A3.91,3.91,0,0,0,16,12Z'></path></svg>"
"</a></li>"
"<li class='cv-switcher-item bx--switcher__item'><a class='cv-switcher-item-link bx--switcher__item-link menitem' href='/configureweather/show'>"
"Configure Weather"
"<svg focusable='false' preserveAspectRatio='xMidYMid meet' xmlns='http://www.w3.org/2000/svg' fill='currentColor' width='16' height='16' viewBox='0 0 32 32' aria-hidden='true'><path d='M24.8008,11.1382a8.9938,8.9938,0,0,0-17.6006,0A6.533,6.533,0,0,0,2,17.5H2V19a1,1,0,0,0,1,1H15a1,1,0,0,0,0-2H4v-.4966H4a4.5176,4.5176,0,0,1,4.144-4.4819l.8155-.064.0991-.812a6.9936,6.9936,0,0,1,13.8838,0l.0986.812.8154.064A4.4962,4.4962,0,0,1,23.5,22H7a1,1,0,0,0,0,2H23.5a6.4963,6.4963,0,0,0,1.3008-12.8618Z'></path><rect width='18' height='2' x='2' y='26' rx='1'></rect></svg>"
"</a></li>"
"<li class='cv-switcher-item bx--switcher__item'><a class='cv-switcher-item-link bx--switcher__item-link menitem' href='/configuresensor/show'>"
"Configure Sensor"
"<svg focusable='false' preserveAspectRatio='xMidYMid meet' xmlns='http://www.w3.org/2000/svg' fill='currentColor' width='16' height='16' viewBox='0 0 32 32' aria-hidden='true'><path d='M30,19H26V15H24v9H8V8l9-.0009V6H13V2H11V6H8A2.002,2.002,0,0,0,6,8v3H2v2H6v6H2v2H6v3a2.0023,2.0023,0,0,0,2,2h3v4h2V26h6v4h2V26h3a2.0027,2.0027,0,0,0,2-2V21h4Z'></path><path d='M26,2a4.0042,4.0042,0,0,0-4,4,3.9556,3.9556,0,0,0,.5668,2.0192L19.5859,11H11V21H21V12.4141l2.9808-2.9808A3.9553,3.9553,0,0,0,26,10a4,4,0,0,0,0-8ZM19,19H13V13h6ZM26,8a2,2,0,1,1,2-2A2.0023,2.0023,0,0,1,26,8Z'></path></svg>"
"</a></li>"
"<li class='cv-switcher-item bx--switcher__item'><a class='cv-switcher-item-link bx--switcher__item-link menitem' href='/systemreset' onclick='return confirm(\"Do you want to reset to default settings?\")'>"
"Reset Settings"
"<svg focusable='false' preserveAspectRatio='xMidYMid meet' xmlns='http://www.w3.org/2000/svg' fill='currentColor' width='16' height='16' viewBox='0 0 32 32' aria-hidden='true'><path d='M18,28A12,12,0,1,0,6,16v6.2L2.4,18.6,1,20l6,6,6-6-1.4-1.4L8,22.2V16H8A10,10,0,1,1,18,26Z'></path></svg>"
"</a></li>"
"<li class='cv-switcher-item bx--switcher__item'><a class='cv-switcher-item-link bx--switcher__item-link menitem' href='/forgetwifi' onclick='return confirm(\"Do you want to forget to WiFi connection?\")'>"
"Forget WiFi"
"<svg focusable='false' preserveAspectRatio='xMidYMid meet' xmlns='http://www.w3.org/2000/svg' fill='currentColor' width='16' height='16' viewBox='0 0 32 32' aria-hidden='true'><circle cx='16' cy='25' r='2'></circle><path d='M30 3.4141L28.5859 2 2 28.5859 3.4141 30 14.0962 19.3179a5.9359 5.9359 0 016.01 1.3193L21.52 19.2236a7.9669 7.9669 0 00-5.125-2.2041l3.3875-3.3877a11.9908 11.9908 0 014.5647 2.7647L25.76 14.9829A13.975 13.975 0 0021.334 12.08L24.3308 9.083a17.9364 17.9364 0 014.2546 3.0747L30 10.7432v-.002a20.02 20.02 0 00-4.1895-3.1377zM14.68 13.0776l2.0415-2.0415C16.481 11.0234 16.2437 11 16 11a13.9447 13.9447 0 00-9.771 3.9927l1.4136 1.4136A11.97 11.97 0 0114.68 13.0776zM16 7a17.87 17.87 0 014.2324.5254L21.875 5.8828A19.9537 19.9537 0 002 10.7412v.0225L3.4043 12.168A17.9193 17.9193 0 0116 7z'></path></svg>"
"</a></li>"
"<li class='cv-switcher-item bx--switcher__item'><a class='cv-switcher-item-link bx--switcher__item-link menitem' href='/update'>"
"Firmware Update"
"<svg focusable='false' preserveAspectRatio='xMidYMid meet' xmlns='http://www.w3.org/2000/svg' fill='currentColor' width='16' height='16' viewBox='0 0 32 32' aria-hidden='true'><path d='M28,12H20V4h8Zm-6-2h4V6H22Z'></path><path d='M17,15V9H9V23H23V15Zm-6-4h4v4H11Zm4,10H11V17h4Zm6,0H17V17h4Z'></path><path d='M26,28H6a2.0023,2.0023,0,0,1-2-2V6A2.0023,2.0023,0,0,1,6,4H16V6H6V26H26V16h2V26A2.0023,2.0023,0,0,1,26,28Z'></path></svg>"
"</a></li>"
"<li class='cv-switcher-item bx--switcher__item'><a class='cv-switcher-item-link bx--switcher__item-link menitem' href='https://github.com/Qrome' target='_blank'>"
"About"
"<svg focusable='false' preserveAspectRatio='xMidYMid meet' xmlns='http://www.w3.org/2000/svg' fill='currentColor' width='16' height='16' viewBox='0 0 32 32' aria-hidden='true'><path d='M16,2A14,14,0,1,0,30,16,14,14,0,0,0,16,2Zm0,26A12,12,0,1,1,28,16,12,12,0,0,1,16,28Z'></path><circle cx='16' cy='23.5' r='1.5'></circle><path d='M17,8H15.5A4.49,4.49,0,0,0,11,12.5V13h2v-.5A2.5,2.5,0,0,1,15.5,10H17a2.5,2.5,0,0,1,0,5H15v4.5h2V17a4.5,4.5,0,0,0,0-9Z'></path></svg>"
"</a></li>";
/**
* Basic header/footer blocks
@ -29,7 +77,9 @@ static const char HEADER_BLOCK2[] PROGMEM = "<link rel='stylesheet' href='https:
"<link rel='stylesheet' href='https://unpkg.com/carbon-components/css/carbon-components.min.css'></style>"
"<link rel='stylesheet' href='https://use.fontawesome.com/releases/v5.15.1/css/all.css'>"
"<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js'></script>"
"<style>.hidden{display:none} .bx--form-item{margin-bottom:20px} .bx--table-column-menu{width: 3.25rem}</style>"
"<script>function showhide(a,b) {var e=$(\"[data-sh='\"+b+\"']\");if(a.checked||a.prop('checked')){e.removeClass('hidden')}else{e.addClass('hidden')}}</script>"
"<style>.hidden{display:none} .bx--form-item{margin-bottom:20px} .bx--table-column-menu{width: 3.25rem} .menitem{padding:6px 1rem;font-size:.875rem;font-weight:600;line-height:1.29;letter-spacing:.16px;display:flex;justify-content:space-between;text-decoration:none;color:#c6c6c6}</style>"
"<script>function openModal(refelementId){document.body.classList.add(\"bx--body--with-modal-open\");document.getElementById(refelementId).classList.add(\"is-visible\")} function closeModal(refelementId){document.getElementById(refelementId).classList.remove(\"is-visible\");document.body.classList.remove(\"bx--body--with-modal-open\")}</script>"
"</head><body>"
"<header class='cv-header bx--header'>"
"<a href='/' class='cv-header-name bx--header__name'>";
@ -38,7 +88,10 @@ static const char HEADER_BLOCK3[] PROGMEM = "</a>"
"<nav class='cv-header-nav bx--header__nav'></nav>"
"<div class='bx--header__global'>"
"<button type='button' class='cv-header-global-action bx--header__action' onclick='openChipInfo()'>"
"<i class='fas fa-microchip' style='color: white; font-size: 20px;'></i>"
"<svg focusable='false' preserveAspectRatio='xMidYMid meet' xmlns='http://www.w3.org/2000/svg' fill='currentColor' width='20' height='20' viewBox='0 0 32 32' aria-hidden='true'>"
"<path d='M11,11V21H21V11Zm8,8H13V13h6Z'></path>"
"<path d='M30,13V11H26V8a2,2,0,0,0-2-2H21V2H19V6H13V2H11V6H8A2,2,0,0,0,6,8v3H2v2H6v6H2v2H6v3a2,2,0,0,0,2,2h3v4h2V26h6v4h2V26h3a2,2,0,0,0,2-2V21h4V19H26V13ZM24,24H8V8H24Z'></path>"
"</svg>"
"</button>"
"<button type='button' class='cv-header-global-action bx--header__action' onclick='openSidebar()'>"
"<svg focusable='false' preserveAspectRatio='xMidYMid meet' xmlns='http://www.w3.org/2000/svg' fill='currentColor' width='20' height='20' viewBox='0 0 32 32' aria-hidden='true'>"
@ -64,8 +117,29 @@ static const char HEADER_BLOCK5[] PROGMEM = "</div>"
"<br><div class='bx--grid bx--grid--full-width' style='margin-top:60px'>"
"<div class='page-header' style='margin-bottom:20px'><h4 class='page-header__label'>";
static const char HEADER_BLOCK_ERROR[] PROGMEM = "<div class='bx--inline-notification bx--inline-notification--error' role='alert' style='max-width:100%'>"
"<div class='bx--inline-notification__details'>"
"<svg focusable='false' preserveAspectRatio='xMidYMid meet' style='will-change: transform;' xmlns='http://www.w3.org/2000/svg' class='bx--inline-notification__icon' width='20' height='20' viewBox='0 0 20 20' aria-hidden='true'><path d='M10,1c-5,0-9,4-9,9s4,9,9,9s9-4,9-9S15,1,10,1z M13.5,14.5l-8-8l1-1l8,8L13.5,14.5z'></path><path d='M13.5,14.5l-8-8l1-1l8,8L13.5,14.5z' data-icon-path='inner-path' opacity='0'></path></svg>"
"<div class='bx--inline-notification__text-wrapper'>"
"<p class='bx--inline-notification__title'>%ERRORMSG%</p>"
"</div>"
"</div>"
"<button data-notification-btn class='bx--inline-notification__close-button' type='button' aria-label='close'>"
"<svg focusable='false' preserveAspectRatio='xMidYMid meet' style='will-change: transform;' xmlns='http://www.w3.org/2000/svg' class='bx--inline-notification__close-icon' width='20' height='20' viewBox='0 0 32 32' aria-hidden='true'><path d='M24 9.4L22.6 8 16 14.6 9.4 8 8 9.4 14.6 16 8 22.6 9.4 24 16 17.4 22.6 24 24 22.6 17.4 16 24 9.4z'></path></svg>"
"</button>"
"</div>";
static const char FOOTER_BLOCK[] PROGMEM = "<br><br><br></div>"
"<div class='bx--loading-overlay hidden' id='pageloading'>"
"<div data-loading class='bx--loading'>"
"<svg class='bx--loading__svg' viewBox='-75 -75 150 150'>"
"<title>Loading</title>"
"<circle class='bx--loading__stroke' cx='0' cy='0' r='37.5' />"
"</svg>"
"</div>"
"</div>"
"<script src='https://unpkg.com/carbon-components/scripts/carbon-components.min.js'></script>"
"<script>$(function(){$('form').on('submit',function(e){$('#pageloading').removeClass('hidden')})})</script>"
"</body>"
"</html>";
@ -114,36 +188,14 @@ static const char UPDATE_FORM[] PROGMEM = "<div class='bx--row'>"
/**
* Controls for weather configuration
*/
static const char WEATHER_FORM1[] PROGMEM = "<form action='/updateweatherconfig' method='get'>"
"<div class='bx--row'>"
"<div class='bx--form-item bx--col bx--col--auto'>"
"<input class='bx--toggle-input bx--toggle-input--small' id='isWeatherEnabled' type='checkbox' name='isWeatherEnabled' %IS_WEATHER_CHECKED%>"
"<label class='bx--toggle-input__label' for='isWeatherEnabled'>"
"<span class='bx--toggle__switch'>"
"<svg class='bx--toggle__check' width='6px' height='5px' viewBox='0 0 6 5'>"
"<path d='M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z' />"
"</svg>"
"<span class='bx--toggle__text--off' aria-hidden='true'>Display Weather when printer is off deactivated</span>"
"<span class='bx--toggle__text--on' aria-hidden='true'>Display Weather when printer is off activated</span>"
"</span>"
"</label>"
"</div>"
"</div>";
static const char WEATHER_FORM_START[] PROGMEM = "<form action='/configureweather/update' method='get'>";
static const char WEATHER_FORM2[] PROGMEM = "<div class='bx--row'>"
"<div class='bx--form-item bx--col bx--col--auto'>"
"<input class='bx--toggle-input bx--toggle-input--small' id='metric' type='checkbox' name='metric' %METRIC%>"
"<label class='bx--toggle-input__label' for='metric'>"
"<span class='bx--toggle__switch'>"
"<svg class='bx--toggle__check' width='6px' height='5px' viewBox='0 0 6 5'>"
"<path d='M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z' />"
"</svg>"
"<span class='bx--toggle__text--on' aria-hidden='true'>Show in Celsius</span>"
"<span class='bx--toggle__text--off' aria-hidden='true'>Show in Fahrenheit</span>"
"</span>"
"</label>"
"</div>"
"</div>";
static const char WEATHER_FORM1_ID[] PROGMEM = "isWeatherEnabled";
static const char WEATHER_FORM1_LABEL[] PROGMEM = "Display Weather when printer is off";
static const char WEATHER_FORM2_ID[] PROGMEM = "metric";
static const char WEATHER_FORM2_LABEL_ON[] PROGMEM = "Show in Celsius";
static const char WEATHER_FORM2_LABEL_OFF[] PROGMEM = "Show in Fahrenheit";
static const char WEATHER_FORM3[] PROGMEM = "<div class='bx--row'>"
"<div class='bx--form-item bx--col bx--col--auto'>"
@ -214,66 +266,19 @@ static const char WEATHER_FORM_OPTIONS[] PROGMEM = "<option class='bx--select-op
/**
* Controls for station configuration
*/
static const char STATION_CONFIG_FORM1[] PROGMEM = "<form action='/updatestationconfig' method='get'>"
"<div class='bx--row'>"
"<div class='bx--col bx--col--auto bx--form-item'>"
"<input class='bx--toggle-input bx--toggle-input--small' id='isClockEnabled' type='checkbox' name='isClockEnabled' %IS_CLOCK_CHECKED%>"
"<label class='bx--toggle-input__label' for='isClockEnabled'>"
"<span class='bx--toggle__switch'>"
"<svg class='bx--toggle__check' width='6px' height='5px' viewBox='0 0 6 5'>"
"<path d='M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z' />"
"</svg>"
"<span class='bx--toggle__text--off' aria-hidden='true'>Display Clock when printer is off deactivated</span>"
"<span class='bx--toggle__text--on' aria-hidden='true'>Display Clock when printer is off activated</span>"
"</span>"
"</label>"
"</div>"
"</div>";
static const char STATION_CONFIG_FORM_START[] PROGMEM = "<form action='/configurestation/update' method='get'>";
static const char STATION_CONFIG_FORM2[] PROGMEM = "<div class='bx--row'>"
"<div class='bx--col bx--col--auto bx--form-item'>"
"<input class='bx--toggle-input bx--toggle-input--small' id='is24hour' type='checkbox' name='is24hour' %IS_24HOUR_CHECKED%>"
"<label class='bx--toggle-input__label' for='is24hour'>"
"<span class='bx--toggle__switch'>"
"<svg class='bx--toggle__check' width='6px' height='5px' viewBox='0 0 6 5'>"
"<path d='M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z' />"
"</svg>"
"<span class='bx--toggle__text--off' aria-hidden='true'>Use 24 Hour Clock (military time) deactivated</span>"
"<span class='bx--toggle__text--on' aria-hidden='true'>Use 24 Hour Clock (military time) activated</span>"
"</span>"
"</label>"
"</div>"
"</div>";
static const char STATION_CONFIG_FORM1_ID[] PROGMEM = "isClockEnabled";
static const char STATION_CONFIG_FORM1_LABEL[] PROGMEM = "Display Clock when printer is off";
static const char STATION_CONFIG_FORM3[] PROGMEM = "<div class='bx--row'>"
"<div class='bx--col bx--col--auto bx--form-item'>"
"<input class='bx--toggle-input bx--toggle-input--small' id='invDisp' type='checkbox' name='invDisp' %IS_INVDISP_CHECKED%>"
"<label class='bx--toggle-input__label' for='invDisp'>"
"<span class='bx--toggle__switch'>"
"<svg class='bx--toggle__check' width='6px' height='5px' viewBox='0 0 6 5'>"
"<path d='M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z' />"
"</svg>"
"<span class='bx--toggle__text--off' aria-hidden='true'>Flip display orientation deactivated</span>"
"<span class='bx--toggle__text--on' aria-hidden='true'>Flip display orientation activated</span>"
"</span>"
"</label>"
"</div>"
"</div>";
static const char STATION_CONFIG_FORM2_ID[] PROGMEM = "is24hour";
static const char STATION_CONFIG_FORM2_LABEL[] PROGMEM = "Use 24 Hour Clock (military time)";
static const char STATION_CONFIG_FORM4[] PROGMEM = "<div class='bx--row'>"
"<div class='bx--col bx--col--auto bx--form-item'>"
"<input class='bx--toggle-input bx--toggle-input--small' id='useFlash' type='checkbox' name='useFlash' %USEFLASH%>"
"<label class='bx--toggle-input__label' for='useFlash'>"
"<span class='bx--toggle__switch'>"
"<svg class='bx--toggle__check' width='6px' height='5px' viewBox='0 0 6 5'>"
"<path d='M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z' />"
"</svg>"
"<span class='bx--toggle__text--off' aria-hidden='true'>Flash System LED on Service Calls deactivated</span>"
"<span class='bx--toggle__text--on' aria-hidden='true'>Flash System LED on Service Calls activated</span>"
"</span>"
"</label>"
"</div>"
"</div>";
static const char STATION_CONFIG_FORM3_ID[] PROGMEM = "invDisp";
static const char STATION_CONFIG_FORM3_LABEL[] PROGMEM = "Flip display orientation";
static const char STATION_CONFIG_FORM4_ID[] PROGMEM = "useFlash";
static const char STATION_CONFIG_FORM4_LABEL[] PROGMEM = "Flash System LED on Service Call";
static const char STATION_CONFIG_FORM5[] PROGMEM = "<div class='bx--row'>"
"<div class='bx--form-item bx--col bx--col--auto bx--select'>"
@ -300,28 +305,16 @@ static const char STATION_CONFIG_FORM6[] PROGMEM = "<div class='bx--row'>"
"</div>"
"</div>";
static const char STATION_CONFIG_FORM7[] PROGMEM = "<div class='bx--row'>"
"<div class='bx--col bx--col--auto bx--form-item'>"
"<input class='bx--toggle-input bx--toggle-input--small' id='isBasicAuth' type='checkbox' name='isBasicAuth' %IS_BASICAUTH_CHECKED%>"
"<label class='bx--toggle-input__label' for='isBasicAuth'>"
"<span class='bx--toggle__switch'>"
"<svg class='bx--toggle__check' width='6px' height='5px' viewBox='0 0 6 5'>"
"<path d='M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z' />"
"</svg>"
"<span class='bx--toggle__text--off' aria-hidden='true'>Use Security Credentials for Configuration Changes deactivated</span>"
"<span class='bx--toggle__text--on' aria-hidden='true'>Use Security Credentials for Configuration Changes activated</span>"
"</span>"
"</label>"
"</div>"
"</div>";
static const char STATION_CONFIG_FORM7_ID[] PROGMEM = "isBasicAuth";
static const char STATION_CONFIG_FORM7_LABEL[] PROGMEM = "Use Security Credentials for Configuration Changes";
static const char STATION_CONFIG_FORM8[] PROGMEM = "<div class='bx--row'>"
static const char STATION_CONFIG_FORM8[] PROGMEM = "<div class='bx--row' data-sh='uspw'>"
"<div class='bx--form-item bx--col bx--col--auto'>"
"<label for='userid' class='bx--label'>User ID (for this interface)</label>"
"<input id='userid' type='text' class='bx--text-input' name='userid' value='%USERID%' maxlength='20'>"
"</div>"
"</div>"
"<div class='bx--row'>"
"<div class='bx--row' data-sh='uspw'>"
"<div class='bx--form-item bx--col bx--col--auto'>"
"<label for='stationpassword' class='bx--label'>Password (for this interface)</label>"
"<input id='stationpassword' type='password' class='bx--text-input' name='stationpassword' value='%STATIONPASSWORD%'>"
@ -332,7 +325,160 @@ static const char STATION_CONFIG_FORM8[] PROGMEM = "<div class='bx--row'>"
"<button class='bx--btn bx--btn--primary' type='submit'>Save</button>"
"</div>"
"</div>"
"</form>";
"</form><script>showhide($('#isBasicAuth'), 'uspw')</script>";
/**
* Controls for printer configuration
*/
static const char CONFPRINTER_FORM_START[] PROGMEM = "<div class='bx--row'>"
"<div class='bx--col bx--col--auto bx--data-table-container' data-table>"
"<div class='bx--data-table-header'>"
"<h4 class='bx--data-table-header__title'>Printers to monitor</h4>"
"<p class='bx--data-table-header__description'>Configurationdata</p>"
"</div>"
"<section class='bx--table-toolbar'>"
"<div class='bx--toolbar-content'>"
"<button class='bx--btn bx--btn--sm bx--btn--primary' onclick='openModal(\"mae-0\")'>"
"Add new"
"<svg focusable='false' preserveAspectRatio='xMidYMid meet' style='will-change: transform;' xmlns='http://www.w3.org/2000/svg' class='bx--btn__icon' width='20' height='20' viewBox='0 0 32 32'><path d='M17 15L17 7 15 7 15 15 7 15 7 17 15 17 15 25 17 25 17 17 25 17 25 15 17 15z'></path></svg>"
"</button>"
"</div>"
"</section>"
"<table class='bx--data-table bx--data-table--visible-overflow-menu'>"
"<thead>"
"<tr>"
"<th><span class='bx--table-header-label'>Name</span></th>"
"<th><span class='bx--table-header-label'>Type</span></th>"
"<th><span class='bx--table-header-label'>State</span></th>"
"<th class='bx--table-column-menu' style='width: 3.25rem'></th>"
"</tr>"
"</thead>"
"<tbody>";
static const char CONFPRINTER_FORM_ROW_ERROR[] PROGMEM = "<div class='bx--tag bx--tag--magenta'>"
"%STATUS%"
"</div>";
static const char CONFPRINTER_FORM_ROW_OK[] PROGMEM = "<div class='bx--tag bx--tag--green'>"
"%STATUS%"
"</div>";
static const char CONFPRINTER_FORM_ROW[] PROGMEM = "<tr>"
"<td>%NAME%</td>"
"<td>%TYPE%</td>"
"<td>%STATE%</td>"
"<td class='bx--table-column-menu' style='width: 3.25rem'>"
"<div data-overflow-menu role='menu' tabindex='0' class='bx--overflow-menu'>"
"<svg focusable='false' preserveAspectRatio='xMidYMid meet' style='will-change: transform;' xmlns='http://www.w3.org/2000/svg' class='bx--overflow-menu__icon' width='16' height='16' viewBox='0 0 16 16' aria-hidden='true'><circle cx='8' cy='3' r='1'></circle><circle cx='8' cy='8' r='1'></circle><circle cx='8' cy='13' r='1'></circle></svg>"
"<ul class='bx--overflow-menu-options bx--overflow-menu--flip' data-floating-menu-direction='bottom'>"
"<li class='bx--overflow-menu-options__option bx--table-row--menu-option'>"
"<button class='bx--overflow-menu-options__btn' onclick='openModal(\"mae-%ID%\")'>"
"<div class='bx--overflow-menu-options__option-content'>"
"<svg focusable='false' preserveAspectRatio='xMidYMid meet' style='will-change: transform;' xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' aria-hidden='true'><path d='M1 13H15V14H1zM12.7 4.5c.4-.4.4-1 0-1.4 0 0 0 0 0 0l-1.8-1.8c-.4-.4-1-.4-1.4 0 0 0 0 0 0 0L2 8.8V12h3.2L12.7 4.5zM10.2 2L12 3.8l-1.5 1.5L8.7 3.5 10.2 2zM3 11V9.2l5-5L9.8 6l-5 5H3z'></path></svg> "
"Edit"
"</div>"
"</button>"
"</li>"
"<li class='bx--overflow-menu-options__option bx--table-row--menu-option'>"
"<button class='bx--overflow-menu-options__btn' onclick='openModal('modal-ed454ftfa4q')'>"
"<div class='bx--overflow-menu-options__option-content'>"
"<svg focusable='false' preserveAspectRatio='xMidYMid meet' style='will-change: transform;' xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' aria-hidden='true'><path d='M6 6H7V12H6zM9 6H10V12H9z'></path><path d='M2 3v1h1v10c0 .6.4 1 1 1h8c.6 0 1-.4 1-1V4h1V3H2zM4 14V4h8v10H4zM6 1H10V2H6z'></path></svg> "
"Delete"
"</div>"
"</button>"
"</li>"
"</ul>"
"</div>"
"</td>"
"</tr>";
static const char CONFPRINTER_FORM_END[] PROGMEM = "</tbody>"
"</table>"
"</div>"
"</div>";
static const char CONFPRINTER_FORM_ADDEDIT_TA[] PROGMEM = "Create new printer";
static const char CONFPRINTER_FORM_ADDEDIT_TE[] PROGMEM = "Edit data for printer";
static const char CONFPRINTER_FORM_ADDEDIT1[] PROGMEM = "<div data-modal id='mae-%ID%' class='bx--modal' role='dialog' aria-modal='true' aria-labelledby='mae-%ID%-label' aria-describedby='mae-%ID%-heading' tabindex='-1'>"
"<div class='bx--modal-container'>"
"<form method='GET' action='/configureprinter/edit'>"
"<input type='hidden' name='id' value='%ID%'>"
"<div class='bx--modal-header'>"
"<p class='bx--modal-header__label bx--type-delta' id='mae-%ID%-label'>Printer Configuration</p>"
"<p class='bx--modal-header__heading bx--type-beta' id='mae-%ID%-heading'>%TITLE%</p>"
"<button class='bx--modal-close' type='button' onclick='closeModal(\"mae-%ID%\")'>"
"<svg focusable='false' preserveAspectRatio='xMidYMid meet' style='will-change: transform;' xmlns='http://www.w3.org/2000/svg' class='bx--modal-close__icon' width='16' height='16' viewBox='0 0 16 16' aria-hidden='true'><path d='M12 4.7L11.3 4 8 7.3 4.7 4 4 4.7 7.3 8 4 11.3 4.7 12 8 8.7 11.3 12 12 11.3 8.7 8z'></path></svg>"
"</button>"
"</div>"
"<div class='bx--modal-content bx--modal-content--with-form'>"
"<div class='bx--form-item'>"
"<label for='e-tname-%ID%' class='bx--label'>Printer Name</label>"
"<input id='e-tname-%ID%' name='e-tname' type='text' class='bx--text-input' placeholder='Custom name' data-modal-primary-focus maxlength='20' value='%NAME%'>"
"</div>"
"<div class='bx--form-item bx--select'>"
"<label for='e-tapi-%ID%' class='bx--label'>API Type</label>"
"<div class='bx--select-input__wrapper'>"
"<select id='e-tapi-%ID%' class='bx--select-input' name='e-tapi'>"
"<option class='bx--select-option' value='0'>Duet</option>"
"<option class='bx--select-option' value='1'>Klipper</option>"
"<option class='bx--select-option' selected value='2'>Octoprint</option>"
"<option class='bx--select-option' value='3'>Repetier</option>"
"</select>"
"<svg focusable='false' preserveAspectRatio='xMidYMid meet' style='will-change: transform;' xmlns='http://www.w3.org/2000/svg' class='bx--select__arrow' width='10' height='6' viewBox='0 0 10 6' aria-hidden='true'><path d='M5 6L0 1 0.7 0.3 5 4.6 9.3 0.3 10 1z'></path></svg>"
"</div>"
"</div>"
"<div class='bx--form-item'>"
"<label for='e-taddr-%ID%' class='bx--label'>Hostname or IP Address (do not include http://)</label>"
"<input id='e-taddr-%ID%' name='e-taddr' type='text' class='bx--text-input' placeholder='Target Address' maxlength='60' value='%TARGETADDR%'>"
"</div>"
"<div class='bx--form-item'>"
"<label for='e-tport-%ID%' class='bx--label'>Port</label>"
"<input id='e-tport-%ID%' name='e-tport' type='text' class='bx--text-input' placeholder='Target port' maxlength='5' value='%TARGETPORT%'>"
"</div>"
"<div class='bx--form-item'>"
"<input class='bx--toggle-input bx--toggle-input--small' id='e-tpsu-%ID%' type='checkbox' name='e-tpsu'>"
"<label class='bx--toggle-input__label' for='e-tpsu-%ID%'>"
"<span class='bx--toggle__switch'>"
"<svg class='bx--toggle__check' width='6px' height='5px' viewBox='0 0 6 5'>"
"<path d='M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z' />"
"</svg>"
"<span class='bx--toggle__text--off' aria-hidden='true'>PSU control deactivated</span>"
"<span class='bx--toggle__text--on' aria-hidden='true'>PSU control activated</span>"
"</span>"
"</label>"
"</div>"
"<div class='bx--form-item'>"
"<input class='bx--toggle-input bx--toggle-input--small' id='e-tapipw-%ID%' type='checkbox' name='e-tapipw' onchange='showhide(this, \"apac-%ID%\")' checked='checked'>"
"<label class='bx--toggle-input__label' for='e-tapipw-%ID%'>"
"<span class='bx--toggle__switch'>"
"<svg class='bx--toggle__check' width='6px' height='5px' viewBox='0 0 6 5'>"
"<path d='M2.2 2.7L5 0 6 1 2.2 5 0 2.7 1 1.5z' />"
"</svg>"
"<span class='bx--toggle__text--off' aria-hidden='true'>Haproxy or basic auth deactivated</span>"
"<span class='bx--toggle__text--on' aria-hidden='true'>Haproxy or basic auth activated</span>"
"</span>"
"</label>"
"</div>"
"<div class='bx--form-item' data-sh='apac-%ID%'>"
"<label for='e-tapiuser-%ID%' class='bx--label'>User ID (for this interface)</label>"
"<input id='e-tapiuser-%ID%' type='text' class='bx--text-input' name='e-tapiuser' value='admin' maxlength='30'>"
"</div>"
"<div class='bx--form-item' data-sh='apac-%ID%'>"
"<label for='e-tapipass-%ID%' class='bx--label'>Password (for this interface)</label>"
"<input id='e-tapipass-%ID%' type='password' class='bx--text-input' name='e-tapipass' value='admin'>"
"</div><br><br>"
"</div>"
"<div class='bx--modal-content--overflow-indicator'></div>"
"<div class='bx--modal-footer'>"
"<button class='bx--btn bx--btn--secondary' type='reset' onclick='closeModal(\"mae-%ID%\")'>Abort</button>"
"<button class='bx--btn bx--btn--primary' type='submit' onclick='closeModal(\"mae-%ID%\")'>Save</button>"
"</div>"
"</form>"
"</div>"
"<span tabindex='0'></span>"
"</div>"
"</div>";
/**
* @brief Class to generate HTML content from Memory
@ -346,4 +492,13 @@ public:
static void sendUpdateForm(ESP8266WebServer *server, GlobalDataController *globalDataController);
static void sendWeatherConfigForm(ESP8266WebServer *server, GlobalDataController *globalDataController);
static void sendStationConfigForm(ESP8266WebServer *server, GlobalDataController *globalDataController);
static void sendPrinterConfigForm(ESP8266WebServer *server, GlobalDataController *globalDataController);
private:
static void sendFormCheckbox(ESP8266WebServer *server, String formId, bool isChecked, String label);
static void sendFormCheckbox(ESP8266WebServer *server, String formId, bool isChecked, String labelOn, String labelOff);
static void sendFormCheckboxEvent(ESP8266WebServer *server, String formId, bool isChecked, String label, String onChange);
static void sendFormCheckboxEvent(ESP8266WebServer *server, String formId, bool isChecked, String labelOn, String labelOff, String onChange);
static void sendPrinterConfigFormAEModal(ESP8266WebServer *server, int id, PrinterDataStruct *forPrinter);
};

View File

@ -3,12 +3,21 @@
String lastMinute = "xx";
String lastSecond = "xx";
int knownPrintersToSync = 0;
int currentRefreshPrinter = 0;
void configModeCallback(WiFiManager *myWiFiManager);
/**
* @brief Setup/Initialize ESP
*/
void setup() {
LittleFS.begin();
debugController.setup();
globalDataController.setPrinterClient(&printerClient);
globalDataController.registerPrinterClient(PRINTER_CLIENT_REPETIER, &printerClient3);
globalDataController.registerPrinterClient(PRINTER_CLIENT_OCTOPRINT, &printerClient2);
globalDataController.registerPrinterClient(PRINTER_CLIENT_KLIPPER, &printerClient1);
globalDataController.registerPrinterClient(PRINTER_CLIENT_DUET, &printerClient0);
globalDataController.setDisplayClient(&displayClient);
globalDataController.setup();
displayClient.preSetup();
@ -33,7 +42,7 @@ void setup() {
// print the received signal strength:
debugController.print("Signal Strength (RSSI): ");
debugController.print(globalDataController.getWifiQuality());
debugController.print(EspController::getWifiQuality());
debugController.printLn("%");
if (ENABLE_OTA) {
@ -76,35 +85,55 @@ void setup() {
debugController.printLn("*** Leaving setup()");
}
/**
* @brief Loop trough all
*/
void loop() {
// Handle update of time
if(timeClient.handleSync(globalDataController.getClockResyncMinutes()) && globalDataController.getWeatherShow()) {
if(timeClient.handleSync(globalDataController.getSystemSettings()->clockWeatherResyncMinutes)
&& globalDataController.getWeatherSettings()->show
) {
// We sync time? Ok, sync weather also!
debugController.printLn("Updating weather...");
weatherClient.updateWeather();
}
if (lastMinute != timeClient.getMinutes() && !printerClient.isPrinting()) {
// Check status every 60 seconds
globalDataController.ledOnOff(true);
lastMinute = timeClient.getMinutes(); // reset the check value
printerClient.getPrinterJobResults();
printerClient.getPrinterPsuState();
globalDataController.ledOnOff(false);
} else if (printerClient.isPrinting()) {
if (lastSecond != timeClient.getSeconds() && timeClient.getSeconds().endsWith("0")) {
lastSecond = timeClient.getSeconds();
// every 10 seconds while printing get an update
globalDataController.ledOnOff(true);
printerClient.getPrinterJobResults();
printerClient.getPrinterPsuState();
globalDataController.ledOnOff(false);
}
// Check printers
if (knownPrintersToSync != globalDataController.getNumPrinters()) {
knownPrintersToSync = globalDataController.getNumPrinters();
currentRefreshPrinter = 0;
}
// Sync only if we have printers
if (knownPrintersToSync > 0) {
if (currentRefreshPrinter >= globalDataController.getNumPrinters()) {
currentRefreshPrinter = 0;
}
PrinterDataStruct *refPrinter = &globalDataController.getPrinterSettings()[currentRefreshPrinter];
bool syncPrinter = false;
if ((refPrinter->lastSyncEpoch == 0)
|| (!refPrinter->isPrinting && (timeClient.getSecondsFromLast(refPrinter->lastSyncEpoch) >= PRINTER_SYNC_SEC))
|| (refPrinter->isPrinting && (timeClient.getSecondsFromLast(refPrinter->lastSyncEpoch) >= PRINTER_SYNC_SEC_PRINTING))
) {
syncPrinter = true;
}
if (syncPrinter) {
globalDataController.ledOnOff(true);
refPrinter->lastSyncEpoch = timeClient.getCurrentEpoch();
globalDataController.syncPrinter(refPrinter);
globalDataController.ledOnOff(false);
}
// Next Time, next printer
currentRefreshPrinter++;
}
// Handle Display
displayClient.handleUpdate();
// Handle all Web stuff
if (WEBSERVER_ENABLED) {
webServer.handleClient();
}
@ -113,6 +142,10 @@ void loop() {
}
}
/**
* @brief AP Mode for WiFi configuration
* @param myWiFiManager
*/
void configModeCallback(WiFiManager *myWiFiManager) {
debugController.printLn("Entered config mode");
debugController.printLn(WiFi.softAPIP().toString());