zmk_mf68/docs/src/pages/power-profiler.js

395 lines
15 KiB
JavaScript
Raw Normal View History

2021-02-17 07:34:09 +11:00
/*
* Copyright (c) 2021 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
import React, { useState } from "react";
import classnames from "classnames";
import Layout from "@theme/Layout";
import styles from "./styles.module.css";
import PowerEstimate from "../components/power-estimate";
import CustomBoardForm from "../components/custom-board-form";
import { useInput } from "../utils/hooks";
import { zmkBoards, backlightLEDs } from "../data/power";
2021-02-17 07:34:09 +11:00
import "../css/power-profiler.css";
const Disclaimer = `This profiler makes many assumptions about typing
activity, battery characteristics, hardware behavior, and
doesn't account for error of user inputs. For example battery
2021-02-17 07:34:09 +11:00
mAh, which is often incorrectly advertised higher than it's actual capacity.
While it tries to estimate power usage using real power readings of ZMK,
2021-02-17 07:34:09 +11:00
every person will have different results that may be worse or even
better than the estimation given here.`;
function PowerProfiler() {
const { value: board, bind: bindBoard } = useInput("");
const { value: split, bind: bindSplit } = useInput(false);
const { value: batteryMilliAh, bind: bindBatteryMilliAh } = useInput(110);
const { value: psuType, bind: bindPsuType } = useInput("");
const { value: outputV, bind: bindOutputV } = useInput(3.3);
const { value: quiescentMicroA, bind: bindQuiescentMicroA } = useInput(55);
const { value: otherQuiescentMicroA, bind: bindOtherQuiescentMicroA } =
useInput(0);
2021-02-17 07:34:09 +11:00
const { value: efficiency, bind: bindEfficiency } = useInput(0.9);
const { value: bondedQty, bind: bindBondedQty } = useInput(1);
const { value: percentAsleep, bind: bindPercentAsleep } = useInput(0.5);
const { value: glowEnabled, bind: bindGlowEnabled } = useInput(false);
const { value: glowQuantity, bind: bindGlowQuantity } = useInput(10);
const { value: glowBrightness, bind: bindGlowBrightness } = useInput(1);
const { value: backlightEnabled, bind: bindBacklightEnabled } =
useInput(false);
const { value: backlightQuantity, bind: bindBacklightQuantity } =
useInput(60);
const { value: backlightColor, bind: bindBacklightColor } = useInput("");
const { value: backlightVoltage, bind: bindBacklightVoltage } = useInput(2.2);
const { value: backlightResistance, bind: bindBacklightResistance } =
useInput(100);
const { value: backlightBrightness, bind: bindBacklightBrightness } =
useInput(1);
2021-02-17 07:34:09 +11:00
const { value: displayEnabled, bind: bindDisplayEnabled } = useInput(false);
const { value: displayType, bind: bindDisplayType } = useInput("");
const [disclaimerAcknowledged, setDisclaimerAcknowledged] = useState(
typeof window !== "undefined"
? localStorage.getItem("zmkPowerProfilerDisclaimer") === "true"
: false
);
const currentBoard =
board === "custom"
? {
powerSupply: {
type: psuType,
outputVoltage: outputV,
quiescentMicroA: quiescentMicroA,
efficiency,
},
otherQuiescentMicroA: otherQuiescentMicroA,
}
: zmkBoards[board];
const currentBacklightVoltage =
backlightColor === "custom"
? backlightVoltage
: backlightLEDs[backlightColor || "White"];
2021-02-17 07:34:09 +11:00
return (
<Layout
title={`ZMK Power Profiler`}
description="Estimate your keyboard's power usage and battery life on ZMK."
>
<header className={classnames("hero hero--primary", styles.heroBanner)}>
<div className="container">
<h1 className="hero__title">ZMK Power Profiler</h1>
<p className="hero__subtitle">
{"Estimate your keyboard's power usage and battery life on ZMK."}
</p>
</div>
</header>
<main>
<section className="container">
<div className="profilerSection">
<h3>Keyboard Specifications</h3>
<div className="row">
<div className="col col--4">
<div className="profilerInput">
<label>Board</label>
<select {...bindBoard}>
<option hidden value="">
Select a board
</option>
{Object.keys(zmkBoards).map((b) => (
<option key={b}>{b}</option>
))}
<option value="custom">Custom</option>
</select>
</div>
</div>
<div className="col col--4">
<div className="profilerInput">
<label>Split Keyboard</label>
<input
id="split"
checked={split}
{...bindSplit}
className="toggleInput"
type="checkbox"
/>
<label htmlFor="split" className="toggle">
<div className="toggleThumb" />
</label>
</div>
</div>
<div className="col col--4">
<div className="profilerInput">
<label>Battery Size</label>
<div className="inputBox">
<input {...bindBatteryMilliAh} type="number" />
<span>mAh</span>
</div>
</div>
</div>
</div>
</div>
{board === "custom" && (
<CustomBoardForm
bindPsuType={bindPsuType}
bindOutputV={bindOutputV}
bindEfficiency={bindEfficiency}
bindQuiescentMicroA={bindQuiescentMicroA}
bindOtherQuiescentMicroA={bindOtherQuiescentMicroA}
/>
)}
<div className="profilerSection">
<h3>Usage Values</h3>
<div className="row">
<div className="col col--4">
<div className="profilerInput">
<label>
Bonded Bluetooth Profiles{" "}
<span tooltip="The average number of host devices connected at once">
</span>
</label>
<input {...bindBondedQty} type="range" min="1" max="5" />
<span>{bondedQty}</span>
</div>
</div>
<div className="col col--4">
<div className="profilerInput">
<label>
Percentage Asleep{" "}
<span tooltip="How much time the keyboard is in deep sleep (15 min. default timeout)">
</span>
</label>
<input
{...bindPercentAsleep}
type="range"
min="0"
step=".1"
max="1"
/>
<span>{Math.round(percentAsleep * 100)}%</span>
</div>
</div>
</div>
</div>
<div className="profilerSection">
<h3>Features</h3>
<div className="row">
<div className="col col--4">
<div className="profilerInput">
<label>RGB Underglow</label>
<input
checked={glowEnabled}
id="glow"
{...bindGlowEnabled}
className="toggleInput"
type="checkbox"
/>
<label htmlFor="glow" className="toggle">
<div className="toggleThumb" />
</label>
</div>
{glowEnabled && (
<>
<div className="profilerInput">
<label>LED Quantity</label>
<div className="inputBox">
<input {...bindGlowQuantity} type="number" />
</div>
</div>
<div className="profilerInput">
<label>Brightness</label>
<input
{...bindGlowBrightness}
type="range"
min="0"
step=".01"
max="1"
/>
<span>{Math.round(glowBrightness * 100)}%</span>
</div>
</>
)}
</div>
<div className="col col--4">
<div className="profilerInput">
<label>Backlight</label>
<input
checked={backlightEnabled}
id="backlight"
{...bindBacklightEnabled}
className="toggleInput"
type="checkbox"
/>
<label htmlFor="backlight" className="toggle">
<div className="toggleThumb" />
</label>
</div>
{backlightEnabled && (
<>
<div className="profilerInput">
<label>LED Quantity</label>
<div className="inputBox">
<input {...bindBacklightQuantity} type="number" />
</div>
</div>
<div className="profilerInput">
<label>LED Forward Voltage</label>
<select {...bindBacklightColor}>
{Object.entries(backlightLEDs).map(([c, v]) => (
<option key={c} value={c}>
{c} ({v.toFixed(1)} V)
</option>
))}
<option value="custom">Custom</option>
</select>
{backlightColor === "custom" && (
<div className="profilerInput">
<div className="inputBox">
<input {...bindBacklightVoltage} type="number" />
<span>V</span>
</div>
</div>
)}
</div>
<div className="profilerInput">
<label>LED Resistance</label>
<div className="inputBox">
<input {...bindBacklightResistance} type="number" />
<span>ohm</span>
</div>
</div>
<div className="profilerInput">
<label>Brightness</label>
<input
{...bindBacklightBrightness}
type="range"
min="0"
step=".01"
max="1"
/>
<span>{Math.round(backlightBrightness * 100)}%</span>
</div>
</>
)}
</div>
2021-02-17 07:34:09 +11:00
<div className="col col--4">
<div className="profilerInput">
<label>Display</label>
<input
checked={displayEnabled}
id="display"
{...bindDisplayEnabled}
className="toggleInput"
type="checkbox"
/>
<label htmlFor="display" className="toggle">
<div className="toggleThumb" />
</label>
</div>
{displayEnabled && (
<div className="profilerInput">
<label>Display Type</label>
<select {...bindDisplayType}>
<option hidden selected>
Select type
</option>
<option value="EPAPER">ePaper</option>
<option value="OLED">OLED</option>
</select>
</div>
)}
</div>
</div>
</div>
{split ? (
<>
<PowerEstimate
board={currentBoard}
splitType="central"
batteryMilliAh={batteryMilliAh}
usage={{ bondedQty, percentAsleep }}
underglow={{ glowEnabled, glowBrightness, glowQuantity }}
backlight={{
backlightEnabled,
backlightVoltage: currentBacklightVoltage,
backlightResistance,
backlightBrightness,
backlightQuantity,
}}
2021-02-17 07:34:09 +11:00
display={{ displayEnabled, displayType }}
/>
<PowerEstimate
board={currentBoard}
splitType="peripheral"
batteryMilliAh={batteryMilliAh}
usage={{ bondedQty, percentAsleep }}
underglow={{ glowEnabled, glowBrightness, glowQuantity }}
backlight={{
backlightEnabled,
backlightVoltage: currentBacklightVoltage,
backlightResistance,
backlightBrightness,
backlightQuantity,
}}
2021-02-17 07:34:09 +11:00
display={{ displayEnabled, displayType }}
/>
</>
) : (
<PowerEstimate
board={currentBoard}
splitType="standalone"
batteryMilliAh={batteryMilliAh}
usage={{ bondedQty, percentAsleep }}
underglow={{ glowEnabled, glowBrightness, glowQuantity }}
backlight={{
backlightEnabled,
backlightVoltage: currentBacklightVoltage,
backlightResistance,
backlightBrightness,
backlightQuantity,
}}
2021-02-17 07:34:09 +11:00
display={{ displayEnabled, displayType }}
/>
)}
<div className="row">
<div className="col col--8 col--offset-2 profilerDisclaimer">
Disclaimer: {Disclaimer}
</div>
</div>
</section>
</main>
{!disclaimerAcknowledged && (
<div className="disclaimerHolder">
<div className="disclaimer">
<h3>Disclaimer</h3>
<p>{Disclaimer}</p>
<button
onClick={() => {
setDisclaimerAcknowledged(true);
localStorage.setItem("zmkPowerProfilerDisclaimer", true);
}}
>
I Understand
</button>
</div>
</div>
)}
</Layout>
);
}
export default PowerProfiler;