Skip to content

Instantly share code, notes, and snippets.

@felixhageloh
Created November 9, 2018 08:02
Show Gist options
  • Save felixhageloh/d9baaf49b5199a252144eb002880ac24 to your computer and use it in GitHub Desktop.
Save felixhageloh/d9baaf49b5199a252144eb002880ac24 to your computer and use it in GitHub Desktop.
A widget displaying co2 levels and current temperature from a home-brew sensor
import { css, run } from "uebersicht";
export const refreshFrequency = 5000;
export const command = dispatch => {
run("curl -s sentir1.local/co2").then(output =>
dispatch({ type: "CO2_FETCHED", output })
);
run("curl -s sentir1.local/temp").then(output =>
dispatch({ type: "TEMP_FETCHED", output })
);
};
export const className = css`
top: 10px;
left: 10px;
position: absolute;
`;
const container = css`
font-family: Ubuntu Mono;
-webkit-backdrop-filter: blur(20px) saturate(150%);
background: rgba(0, 0, 0, 0.8);
padding: 30px 20px 15px 20px;
border-radius: 3px;
`;
const chart = css`
margin: 0;
padding: 0;
height: 100px;
width: 348px;
display: flex;
align-items: flex-end;
position: relative;
`;
const chartWrapper = css`
position: relative;
`;
const mark = css`
position: absolute;
border-top: 0.5px dashed #666;
width: 100%;
left: 0;
bottom: 0;
`;
const mark600 = css(mark, { bottom: "30%" });
const mark1000 = css(mark, { bottom: "50%", borderColor: "#be4a3f" });
const markTop = css(mark, { bottom: "100%" });
const bar = css`
width: 5px;
flex-shrink: 0;
background: #fff;
border-radius: 1px 1px 0 0;
list-style-type: none;
margin-right: 2px;
`;
const header = css`
margin: 12px 0 4px 0;
font-size: 22px;
font-family: Ubuntu Mono;
`;
const label = css`
margin: 0;
opacity: 0.8;
font-size: 12px;
font-family: Ubuntu Mono;
text-transform: uppercase;
color: #fff;
`;
const details = css`
display: flex;
`;
const co2Details = css`
color: #fff;
margin-right: 40px;
`;
const tempDetails = css`
color: #fff;
`;
const storedLevels = localStorage.getItem("co2State");
export const initialState = storedLevels
? JSON.parse(storedLevels)
: { levels: [], counter: 0 };
function updateCo2(output, state) {
const l = parseInt(output, 10);
let { levels, counter } = state;
if (counter % sampleRate === 0) {
levels = levels.length >= 50 ? levels.slice(1).concat(l) : levels.concat(l);
counter = 0;
}
const newState = {
...state,
level: l,
levels: levels || [],
counter: counter + 1
};
localStorage.setItem("co2State", JSON.stringify(newState));
return newState;
}
function updateTemp(output, state) {
return { ...state, temp: parseInt(output, 10) };
}
const sampleRate = 100;
export function updateState({ type, output }, state) {
switch (type) {
case "CO2_FETCHED":
return updateCo2(output, state);
case "TEMP_FETCHED":
return updateTemp(output, state);
default: {
return state;
}
}
}
function Bar({ level }) {
const height = (level / 2000) * 100 + "%";
const color = `hsla(206, 7%, ${(level / 2000) * 100}%, 0.9)`;
const background = color;
return <li className={bar} style={{ height, background }} />;
}
export function render(props) {
if (isNaN(props.level)) {
return (
<div className={container}>
<p className={label}>Sensor Offline</p>
</div>
);
}
return (
<div className={container}>
<div className={chartWrapper}>
<div className={mark} />
<div className={mark600} />
<div className={mark1000} />
<div className={markTop} />
<ul className={chart}>
{props.levels.map((l, i) => (
<Bar key={i} level={l} />
))}
</ul>
</div>
<div className={details}>
<div className={co2Details}>
<h3 className={header}>{props.level}</h3>
<p className={label}>co2 ppm</p>
</div>
<div className={tempDetails}>
<h3 className={header}>{props.temp}</h3>
<p className={label}>°C</p>
</div>
</div>
</div>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment