mirror of
https://github.com/ckaczor/Blog.git
synced 2026-01-13 17:22:16 -05:00
616 lines
16 KiB
HTML
616 lines
16 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Laundry Monitor - Hardware</title>
|
||
<meta name="description" content="Code, Critters, and whatever I feel like writing about.">
|
||
<link rel="alternate" href="/feed/feed.xml" type="application/atom+xml" title="Chris Kaczor">
|
||
|
||
<link rel="apple-touch-icon" sizes="180x180" href="/img/apple-touch-icon.png?v=2">
|
||
<link rel="icon" type="image/png" sizes="32x32" href="/img/favicon-32x32.png?v=2">
|
||
<link rel="icon" type="image/png" sizes="16x16" href="/img/favicon-16x16.png?v=2">
|
||
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
|
||
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
|
||
|
||
<meta name="generator" content="Eleventy v3.0.0">
|
||
|
||
|
||
<style>
|
||
/**
|
||
* okaidia theme for JavaScript, CSS and HTML
|
||
* Loosely based on Monokai textmate theme by http://www.monokai.nl/
|
||
* @author ocodia
|
||
*/
|
||
|
||
code[class*="language-"],
|
||
pre[class*="language-"] {
|
||
color: #f8f8f2;
|
||
background: none;
|
||
text-shadow: 0 1px rgba(0, 0, 0, 0.3);
|
||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||
font-size: 1em;
|
||
text-align: left;
|
||
white-space: pre;
|
||
word-spacing: normal;
|
||
word-break: normal;
|
||
word-wrap: normal;
|
||
line-height: 1.5;
|
||
|
||
-moz-tab-size: 4;
|
||
-o-tab-size: 4;
|
||
tab-size: 4;
|
||
|
||
-webkit-hyphens: none;
|
||
-moz-hyphens: none;
|
||
-ms-hyphens: none;
|
||
hyphens: none;
|
||
}
|
||
|
||
/* Code blocks */
|
||
pre[class*="language-"] {
|
||
padding: 1em;
|
||
margin: .5em 0;
|
||
overflow: auto;
|
||
border-radius: 0.3em;
|
||
}
|
||
|
||
:not(pre) > code[class*="language-"],
|
||
pre[class*="language-"] {
|
||
background: #272822;
|
||
}
|
||
|
||
/* Inline code */
|
||
:not(pre) > code[class*="language-"] {
|
||
padding: .1em;
|
||
border-radius: .3em;
|
||
white-space: normal;
|
||
}
|
||
|
||
.token.comment,
|
||
.token.prolog,
|
||
.token.doctype,
|
||
.token.cdata {
|
||
color: #8292a2;
|
||
}
|
||
|
||
.token.punctuation {
|
||
color: #f8f8f2;
|
||
}
|
||
|
||
.token.namespace {
|
||
opacity: .7;
|
||
}
|
||
|
||
.token.property,
|
||
.token.tag,
|
||
.token.constant,
|
||
.token.symbol,
|
||
.token.deleted {
|
||
color: #f92672;
|
||
}
|
||
|
||
.token.boolean,
|
||
.token.number {
|
||
color: #ae81ff;
|
||
}
|
||
|
||
.token.selector,
|
||
.token.attr-name,
|
||
.token.string,
|
||
.token.char,
|
||
.token.builtin,
|
||
.token.inserted {
|
||
color: #a6e22e;
|
||
}
|
||
|
||
.token.operator,
|
||
.token.entity,
|
||
.token.url,
|
||
.language-css .token.string,
|
||
.style .token.string,
|
||
.token.variable {
|
||
color: #f8f8f2;
|
||
}
|
||
|
||
.token.atrule,
|
||
.token.attr-value,
|
||
.token.function,
|
||
.token.class-name {
|
||
color: #e6db74;
|
||
}
|
||
|
||
.token.keyword {
|
||
color: #66d9ef;
|
||
}
|
||
|
||
.token.regex,
|
||
.token.important {
|
||
color: #fd971f;
|
||
}
|
||
|
||
.token.important,
|
||
.token.bold {
|
||
font-weight: bold;
|
||
}
|
||
.token.italic {
|
||
font-style: italic;
|
||
}
|
||
|
||
.token.entity {
|
||
cursor: help;
|
||
}
|
||
/*
|
||
* New diff- syntax
|
||
*/
|
||
|
||
pre[class*='language-diff-'] {
|
||
--eleventy-code-padding: 1.25em;
|
||
padding-left: var(--eleventy-code-padding);
|
||
padding-right: var(--eleventy-code-padding);
|
||
}
|
||
.token.deleted {
|
||
background-color: hsl(0, 51%, 37%);
|
||
color: inherit;
|
||
}
|
||
.token.inserted {
|
||
background-color: hsl(126, 31%, 39%);
|
||
color: inherit;
|
||
}
|
||
|
||
/* Make the + and - characters unselectable for copy/paste */
|
||
.token.prefix.unchanged,
|
||
.token.prefix.inserted,
|
||
.token.prefix.deleted {
|
||
-webkit-user-select: none;
|
||
user-select: none;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding-top: 2px;
|
||
padding-bottom: 2px;
|
||
}
|
||
.token.prefix.inserted,
|
||
.token.prefix.deleted {
|
||
width: var(--eleventy-code-padding);
|
||
background-color: rgba(0, 0, 0, 0.2);
|
||
}
|
||
|
||
/* Optional: full-width background color */
|
||
.token.inserted:not(.prefix),
|
||
.token.deleted:not(.prefix) {
|
||
display: block;
|
||
margin-left: calc(-1 * var(--eleventy-code-padding));
|
||
margin-right: calc(-1 * var(--eleventy-code-padding));
|
||
text-decoration: none; /* override del, ins, mark defaults */
|
||
color: inherit; /* override del, ins, mark defaults */
|
||
}
|
||
/* Defaults */
|
||
:root {
|
||
--font-family: Roboto, sans-serif;
|
||
--font-family-monospace: Consolas, Menlo, Monaco, Andale Mono WT,
|
||
Andale Mono, Lucida Console, Lucida Sans Typewriter, DejaVu Sans Mono,
|
||
Bitstream Vera Sans Mono, Liberation Mono, Nimbus Mono L, Courier New,
|
||
Courier, monospace;
|
||
}
|
||
|
||
/* Theme colors */
|
||
:root {
|
||
--color-gray-20: #e0e0e0;
|
||
--color-gray-50: #c0c0c0;
|
||
--color-gray-90: #333;
|
||
|
||
--background-color: #fff;
|
||
|
||
--text-color: var(--color-gray-90);
|
||
--text-color-link: #082840;
|
||
--text-color-link-active: #5f2b48;
|
||
--text-color-link-visited: #17050f;
|
||
|
||
--syntax-tab-size: 2;
|
||
}
|
||
|
||
@media (prefers-color-scheme: dark) {
|
||
:root {
|
||
--color-gray-20: #e0e0e0;
|
||
--color-gray-50: #c0c0c0;
|
||
--color-gray-90: #dad8d8;
|
||
|
||
/* --text-color is assigned to --color-gray-_ above */
|
||
--text-color-link: #1493fb;
|
||
--text-color-link-active: #6969f7;
|
||
--text-color-link-visited: #a6a6f8;
|
||
|
||
--background-color: #15202b;
|
||
}
|
||
}
|
||
|
||
/* Global stylesheet */
|
||
* {
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
@view-transition {
|
||
navigation: auto;
|
||
}
|
||
|
||
html,
|
||
body {
|
||
padding: 0;
|
||
margin: 0 auto;
|
||
font-family: var(--font-family);
|
||
color: var(--text-color);
|
||
background-color: var(--background-color);
|
||
}
|
||
html {
|
||
overflow-y: scroll;
|
||
}
|
||
body {
|
||
max-width: 60em;
|
||
}
|
||
|
||
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
|
||
.visually-hidden {
|
||
clip: rect(0 0 0 0);
|
||
clip-path: inset(50%);
|
||
height: 1px;
|
||
overflow: hidden;
|
||
position: absolute;
|
||
white-space: nowrap;
|
||
width: 1px;
|
||
}
|
||
|
||
p:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
p {
|
||
line-height: 1.5;
|
||
}
|
||
|
||
li {
|
||
line-height: 1.5;
|
||
}
|
||
|
||
a[href] {
|
||
color: var(--text-color-link);
|
||
}
|
||
a[href]:visited {
|
||
color: var(--text-color-link-visited);
|
||
}
|
||
a[href]:hover,
|
||
a[href]:active {
|
||
color: var(--text-color-link-active);
|
||
}
|
||
|
||
main {
|
||
padding: 1rem;
|
||
}
|
||
footer {
|
||
padding-bottom: 1rem;
|
||
padding-left: 1rem;
|
||
padding-right: 1rem;
|
||
font-size: 0.75rem;
|
||
}
|
||
main :first-child {
|
||
margin-top: 0;
|
||
}
|
||
|
||
header {
|
||
border-bottom: 1px dashed var(--color-gray-20);
|
||
}
|
||
header:after {
|
||
content: '';
|
||
display: table;
|
||
clear: both;
|
||
}
|
||
|
||
.links-nextprev {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
gap: 0.5em 1em;
|
||
list-style: '';
|
||
border-top: 1px dashed var(--color-gray-20);
|
||
padding: 1em 0;
|
||
}
|
||
.links-nextprev > * {
|
||
flex-grow: 1;
|
||
}
|
||
.links-nextprev-next {
|
||
text-align: right;
|
||
}
|
||
|
||
table {
|
||
margin: 1em 0;
|
||
}
|
||
table td,
|
||
table th {
|
||
padding-right: 1em;
|
||
}
|
||
|
||
pre,
|
||
code {
|
||
font-family: var(--font-family-monospace);
|
||
}
|
||
pre:not([class*='language-']) {
|
||
margin: 0.5em 0;
|
||
line-height: 1.375; /* 22px /16 */
|
||
-moz-tab-size: var(--syntax-tab-size);
|
||
-o-tab-size: var(--syntax-tab-size);
|
||
tab-size: var(--syntax-tab-size);
|
||
-webkit-hyphens: none;
|
||
-ms-hyphens: none;
|
||
hyphens: none;
|
||
direction: ltr;
|
||
text-align: left;
|
||
white-space: pre;
|
||
word-spacing: normal;
|
||
word-break: normal;
|
||
overflow-x: auto;
|
||
}
|
||
code {
|
||
word-break: break-all;
|
||
}
|
||
|
||
/* Header */
|
||
header {
|
||
display: flex;
|
||
gap: 1em 0.5em;
|
||
flex-wrap: wrap;
|
||
align-items: center;
|
||
padding: 1em;
|
||
}
|
||
.home-link {
|
||
font-size: 1em; /* 16px /16 */
|
||
font-weight: 700;
|
||
margin-right: 2em;
|
||
}
|
||
.home-link:link:not(:hover) {
|
||
text-decoration: none;
|
||
}
|
||
|
||
/* Nav */
|
||
.nav {
|
||
display: flex;
|
||
padding: 0;
|
||
margin: 0;
|
||
list-style: none;
|
||
}
|
||
.nav-item {
|
||
display: inline-block;
|
||
margin-right: 1em;
|
||
}
|
||
.nav-item a[href]:not(:hover) {
|
||
text-decoration: none;
|
||
}
|
||
.nav a[href][aria-current='page'] {
|
||
font-weight: bold;
|
||
}
|
||
|
||
/* Posts list */
|
||
.postlist {
|
||
list-style: none;
|
||
padding: 0;
|
||
}
|
||
.postlist-item {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
align-items: baseline;
|
||
margin-bottom: 2em;
|
||
}
|
||
.postlist-item:last-child {
|
||
margin-bottom: 0em;
|
||
}
|
||
.postlist-item:before {
|
||
display: inline-block;
|
||
pointer-events: none;
|
||
line-height: 100%;
|
||
text-align: right;
|
||
}
|
||
.postlist-date,
|
||
.postlist-item:before {
|
||
font-size: 0.8125em; /* 13px /16 */
|
||
color: var(--color-gray-90);
|
||
}
|
||
.postlist-date {
|
||
word-spacing: -0.5px;
|
||
}
|
||
.postlist-link {
|
||
font-size: 1.1875em; /* 19px /16 */
|
||
font-weight: 700;
|
||
flex-basis: calc(100% - 1.5rem);
|
||
padding-right: 0.5em;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.postlist-read-more {
|
||
text-decoration: none;
|
||
font-size: 0.8125em;
|
||
flex-basis: 100%;
|
||
}
|
||
|
||
.postlist-read-more:hover {
|
||
text-decoration: underline;
|
||
}
|
||
|
||
.postlist-link:hover {
|
||
text-decoration: underline;
|
||
text-underline-position: from-font;
|
||
text-underline-offset: 0;
|
||
text-decoration-thickness: 1px;
|
||
}
|
||
.postlist-item-active .postlist-link {
|
||
font-weight: bold;
|
||
}
|
||
|
||
.postlist-byline {
|
||
flex-basis: 100%;
|
||
}
|
||
|
||
.postlist-tags {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
list-style-type: none;
|
||
gap: 0.5em;
|
||
font-size: 0.8125em;
|
||
padding-inline-start: 10px;
|
||
}
|
||
|
||
.postlist-tag {
|
||
text-decoration: none;
|
||
}
|
||
|
||
.postlist-tag:hover {
|
||
text-decoration: underline;
|
||
}
|
||
|
||
/* Tags */
|
||
.post-tag {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
text-transform: capitalize;
|
||
}
|
||
.postlist-item > .post-tag {
|
||
align-self: center;
|
||
}
|
||
|
||
/* Tags list */
|
||
.post-metadata {
|
||
display: inline-flex;
|
||
flex-wrap: wrap;
|
||
gap: 0.5em;
|
||
list-style: none;
|
||
padding: 0;
|
||
margin: 0;
|
||
}
|
||
.post-metadata time {
|
||
margin-right: 1em;
|
||
}
|
||
|
||
img {
|
||
max-width: 100%;
|
||
display: block;
|
||
margin: 0 auto;
|
||
}
|
||
img[height] {
|
||
height: auto;
|
||
}
|
||
img[width][height] {
|
||
height: auto;
|
||
}
|
||
|
||
.footer-links {
|
||
display: flex;
|
||
justify-content: center;
|
||
margin-top: 1rem;
|
||
height: 2rem;
|
||
column-gap: 1rem;
|
||
|
||
img {
|
||
height: 2rem;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<a href="#skip" class="visually-hidden">Skip to main content</a>
|
||
|
||
<header>
|
||
<a href="/" class="home-link">Chris Kaczor</a>
|
||
<nav>
|
||
<h2 class="visually-hidden" id="top-level-navigation-menu">Top level navigation menu</h2>
|
||
<ul class="nav">
|
||
<li class="nav-item">
|
||
<a href="/">
|
||
Home
|
||
</a>
|
||
</li>
|
||
<li class="nav-item">
|
||
<a href="/tags/">
|
||
Tags
|
||
</a>
|
||
</li>
|
||
<li class="nav-item">
|
||
<a href="/about/">
|
||
About
|
||
</a>
|
||
</li>
|
||
</ul>
|
||
</nav>
|
||
</header>
|
||
|
||
<main id="skip">
|
||
<heading-anchors>
|
||
|
||
<h1 id="laundry-monitor-hardware">Laundry Monitor - Hardware</h1>
|
||
|
||
<ul class="post-metadata">
|
||
<li>
|
||
<time datetime="2018-03-29">29 March 2018</time>
|
||
</li>
|
||
<li>
|
||
<a href="/tags/code/" class="post-tag">Code</a>
|
||
</li>
|
||
</ul>
|
||
|
||
<p>The next project up is <a href="https://github.com/ckaczor/LaundryMonitor">LaundryMonitor</a> which uses the most hardware of anything I've done so far.</p>
|
||
<p>I'd always wanted something that would let us tell if the washing machine or dryer was running but I never knew exactly the right way to detect it. After we got our solar panels I was doing research on how to track power usage and came across an article about current sensors and had the idea that I could hook up a current sensor to each appliance and watch the output voltage to know if the appliance was running. While trying to find a decent sensor I stumbled across a current switch which was more or less the same idea but had everything in one package - when the current was over a certain threshold the switch would close and that could be easily detected.</p>
|
||
<p>My first thought was to use a <a href="http://www.powerswitchtail.com/powerstate-tail">PowerState Tail</a> but only a 120V version was available - there was nothing like it I could use for the 240V of the dryer. Eventually I settled on a <a href="https://smile.amazon.com/gp/product/B00I9IFJOM/ref=oh_aui_search_detailpage?ie=UTF8&psc=1">Dwyer Miniature Current Switch</a> and I'd use one each for both the washer and dryer just to be consistent.</p>
|
||
<p>Next up was to figure out how to monitor the switch. I was going to use a <a href="https://www.phidgets.com/?tier=1&catid=2&pcid=1">Phidget I/O Board</a> attached to a central server and run wires across the house from the washer and dryer to the I/O board but the idea of running all the wires wasn't too appealing. I was about to try some sort of <a href="https://www.sparkfun.com/pages/xbee_guide">XBee</a> setup when I found the <a href="https://getchip.com/pages/chip">C.H.I.P.</a> Kickstarter and it seemed like it was worth a try - the C.H.I.P. was cheap, had digital I/O, had WiFi, and I could use anything that'd run on Linux to make it all work. The full board is probably a bit of overkill for just monitoring two switches but at $9 a device it really didn't bother me that much.</p>
|
||
<p>Hooking up the dryer was relatively easy - I opened the control panel, used the schematic to find the wire that powers the motor, disconnected the wire, ran the wire through the current switch, and reconnected the wire. I mounted the sensor on the back of the dryer for easy access in case I needed to adjust it but the motor draws enough current that the switch was able to detect it easily.</p>
|
||
<p><a href="/blog/laundry-monitor-hardware/images/Dryer.jpg"><picture><source type="image/avif" srcset="/img/7D8kV0Tyqw-225.avif 225w"><source type="image/webp" srcset="/img/7D8kV0Tyqw-225.webp 225w"><img loading="lazy" decoding="async" src="/img/7D8kV0Tyqw-225.jpeg" alt="" width="225" height="300"></picture></a></p>
|
||
<p>The washer was pretty much the same but I decided to monitor the main power line so I could detect if the washer was running at any point in the cycle. The trouble was that at certain times (like when the washer was filling) the current draw was way too low for the switch to detect even with the sensitivity set as low as possible. I solved this by looping the wire through the sensor several times to amplify the current to the point where the switch could pick it up.</p>
|
||
<p><a href="/blog/laundry-monitor-hardware/images/Washer.jpg"><picture><source type="image/avif" srcset="/img/Qvfav4t14w-225.avif 225w"><source type="image/webp" srcset="/img/Qvfav4t14w-225.webp 225w"><img loading="lazy" decoding="async" src="/img/Qvfav4t14w-225.jpeg" alt="" width="225" height="300"></picture></a></p>
|
||
<p>From here on out things were simple - I just had to run some smaller wires from the switch to the digital I/O ports on the C.H.I.P. and then start working on the software. I ended up sticking the C.H.I.P. a few feet away by the power outlet so I didn't need too long a USB cable to power it.</p>
|
||
<p><a href="/blog/laundry-monitor-hardware/images/Chip.jpg"><picture><source type="image/avif" srcset="/img/y6v3-1HpL1-225.avif 225w"><source type="image/webp" srcset="/img/y6v3-1HpL1-225.webp 225w"><img loading="lazy" decoding="async" src="/img/y6v3-1HpL1-225.jpeg" alt="" width="225" height="300"></picture></a></p>
|
||
<p>So far this has been running for a little over two years and the hardware continues to work well. I'm planning to do a similar build to monitor two sump pumps - the only change is that I'm planning to use the PowerState Tail since they're both 120V with standard plugs so it'll be a lot easier to hook up.</p>
|
||
<p>I'll cover the software side of the project in my next post - right now the monitor is a standalone service that does all the work but since I'm going to be adding more devices I'm thinking that I need to break things up a bit.</p>
|
||
|
||
<ul class="links-nextprev">
|
||
<li class="links-nextprev-prev">← Previous<br>
|
||
<a href="/blog/work-indicator/">Work Indicator</a>
|
||
</li>
|
||
|
||
<li class="links-nextprev-next">Next →<br>
|
||
<a href="/blog/laundry-monitor-software/">Laundry Monitor – Software</a>
|
||
</li>
|
||
|
||
</ul>
|
||
</heading-anchors>
|
||
</main>
|
||
|
||
<footer>
|
||
<div class="footer-links">
|
||
<a href="https://github.com/ckaczor" title="GitHub">
|
||
<picture>
|
||
<source srcset="/img/github/github-mark.svg" media="(prefers-color-scheme: light)">
|
||
<source srcset="/img/github/github-mark-white.svg" media="(prefers-color-scheme: dark)">
|
||
<img src="/img/github/github-mark.svg" alt="GitHub Logo">
|
||
</picture>
|
||
</a>
|
||
<a href="/feed/feed.xml" type="application/atom+xml" title="Subscribe">
|
||
<picture>
|
||
<source srcset="/img/feed/rss.svg" media="(prefers-color-scheme: light)">
|
||
<source srcset="/img/feed/rss-white.svg" media="(prefers-color-scheme: dark)">
|
||
<img src="/img/feed/rss.svg" alt="RSS">
|
||
</picture>
|
||
</a>
|
||
<a href="https://www.linkedin.com/in/chris-kaczor/" title="LinkedIn">
|
||
<picture>
|
||
<source srcset="/img/linkedin/linkedin.svg" media="(prefers-color-scheme: light)">
|
||
<source srcset="/img/linkedin/linkedin-white.svg" media="(prefers-color-scheme: dark)">
|
||
<img src="/img/linkedin/linkedin.svg" alt="LinkedIn">
|
||
</picture>
|
||
</a>
|
||
</div>
|
||
</footer>
|
||
|
||
<!-- This page `/blog/laundry-monitor-hardware/` was built on 2024-11-25T16:32:59.377Z -->
|
||
<!-- Built with Eleventy v3.0.0 -->
|
||
<script type="module" src="/dist/rJ3_G-2ArF.js"></script>
|
||
</body>
|
||
</html>
|