Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Unreleased

### English
- **"🌐 AxeOS" button on each Bitaxe card:** opens the miner's own AxeOS page by IP (the address AxeOS reports, falling back to the registered host), since `.local` names don't open on every phone. The IP is shown on the button.
- **Umbrel app (community store):** the `umbrel/` folder is an Umbrel community app store with HomeMinerProxy (dashboard behind Umbrel's login, Stratum ports open on the Umbrel's IP, data in the app folder, multi-arch image from GHCR). See `umbrel/README.md`. The Docker image now also exposes ports 3340 and 3341.
- **Record sound ("tam-tam-tam-tammm"):** the record celebration now plays a short fanfare in the browser, generated live with Web Audio (no audio file): the full fanfare for a farm record, a short "tam-tammm" for a personal one. 🔊/🔇 in the top bar turns it on or off (remembered per browser). Browsers only allow sound after a tap on the page; for kiosk mode, start Chromium with `--autoplay-policy=no-user-gesture-required`.
- **Bitaxe "regulator hot" alert at 95 °C (was 80 °C):** the first real Gamma 602 runs its voltage regulator at ~82 °C with the chip at 60 °C, which is normal; the old limit fired a false alarm. AxeOS itself stops hashing only above 105 °C (and resumes at 95 °C), so 95 °C warns before that.
Expand All @@ -27,6 +28,7 @@
- Fixed in Settings: "Use these" after the Bitaxe scan always named them bitaxe1, bitaxe2… instead of their worker name, and a Sonoff address with a port (`host:8081`) was refused in the browser.

### Português
- **Botão "🌐 AxeOS" em cada cartão do Bitaxe:** abre a página do próprio AxeOS pelo IP (o endereço que o AxeOS informa; sem ele, o host cadastrado), porque nome `.local` não abre em todo celular. O IP aparece no botão.
- **App para Umbrel (loja comunitária):** a pasta `umbrel/` é uma loja comunitária do Umbrel com o HomeMinerProxy (painel atrás do login do Umbrel, portas Stratum abertas no IP do Umbrel, dados na pasta do app, imagem multi-arquitetura do GHCR). Veja `umbrel/README.md`. A imagem Docker também passa a expor as portas 3340 e 3341.
- **Som de recorde ("tam-tam-tam-tammm"):** a comemoração de recorde agora toca uma fanfarra curta no navegador, gerada na hora com Web Audio (sem arquivo de áudio): a fanfarra inteira no recorde da fazenda, um "tam-tammm" curto no recorde pessoal. O 🔊/🔇 da barra superior liga ou desliga (fica guardado em cada navegador). Os navegadores só liberam som depois de um toque na página; no modo quiosque, abra o Chromium com `--autoplay-policy=no-user-gesture-required`.
- **Alerta "regulador quente" do Bitaxe em 95 °C (era 80 °C):** o primeiro Gamma 602 de verdade trabalha com o regulador a ~82 °C e o chip a 60 °C, o que é normal; o limite antigo dava alarme falso. O próprio AxeOS só para de minerar acima de 105 °C (e volta a 95 °C), então 95 °C avisa antes disso.
Expand Down
2 changes: 2 additions & 0 deletions src/bitaxe.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ function normalize(j) {
board: j.boardVersion || null,
version: j.version || null,
hostname: j.hostname || null,
// IP que o próprio AxeOS informa (2.x): o link abre por ele, porque nome .local não resolve em todo celular
ip: [j.ipv4, j.ip].find((v) => typeof v === 'string' && /^\d{1,3}(\.\d{1,3}){3}$/.test(v)) || null,
hashRate,
hashRate1m: ghs(j.hashRate_1m),
hashRate10m: ghs(j.hashRate_10m),
Expand Down
4 changes: 2 additions & 2 deletions src/i18n.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions src/painel.js
Original file line number Diff line number Diff line change
Expand Up @@ -1202,6 +1202,8 @@ const PAGE = `<!doctype html>
.bx .bxh { display:flex; flex-wrap:wrap; gap:6px 10px; align-items:baseline; }
.bx .bxh b { font-size:15px; }
.bx .bxh a { margin-left:auto; font-size:12px; color:var(--dim); }
.bx .bxh a.axeos { font-size:13px; color:var(--ok); border:1px solid var(--line); border-radius:8px; padding:3px 9px; text-decoration:none; }
.bx .bxh a.axeos span { color:var(--dim); }
.bxg { display:grid; grid-template-columns:repeat(auto-fill, minmax(150px, 1fr)); gap:8px 14px; margin-top:8px; }
.bxg div { font-size:14px; }
.bxg span { display:block; font-size:11px; color:var(--dim); }
Expand Down Expand Up @@ -1783,7 +1785,7 @@ function renderProxyExtras(p) {
ul.innerHTML = (p.events || []).map((e) => '<li>' + (icon[e.type] || '•') + ' ' + hora(e.at) + ' — ' + esc(e.msg) + '</li>').join('') || '<li>nenhum evento ainda</li>';
}

const BXT = { noAnswer: 'sem resposta', hash: 'Hashrate (10 min)', of: 'de', expected: 'esperado', chip: 'Chip', vr: 'Regulador', power: 'Consumo', fan: 'Fan', freq: 'Frequência', pool: 'Pool', backup: 'reserva', best: 'Melhor da sessão', up: 'Ligado há', wifi: 'Wi-Fi', paused: 'pausado', overheat: 'superaquecido: o AxeOS baixou a frequência', powerFault: 'falha de energia (confira a fonte)', hwFault: 'falha de hardware', open: 'abrir o AxeOS ↗', last: 'última leitura', hot: 'chip quente', vrhot: 'regulador quente', lowhash: 'hashrate baixo', onBackup: 'na pool reserva', reboots: 'reinícios', lastAct: 'Última ação', acts: { restart: 'reiniciar', identify: 'identificar', pause: 'pausar', resume: 'retomar', fan: 'fan', point: 'apontar para o proxy' }, actFail: 'falhou', actions: 'ações ⚙️', chHash: 'Hashrate · 24 h', chTemp: 'Chip · 24 h', chWait: 'o gráfico aparece depois de 10 min de leituras' };
const BXT = { noAnswer: 'sem resposta', hash: 'Hashrate (10 min)', of: 'de', expected: 'esperado', chip: 'Chip', vr: 'Regulador', power: 'Consumo', fan: 'Fan', freq: 'Frequência', pool: 'Pool', backup: 'reserva', best: 'Melhor da sessão', up: 'Ligado há', wifi: 'Wi-Fi', paused: 'pausado', overheat: 'superaquecido: o AxeOS baixou a frequência', powerFault: 'falha de energia (confira a fonte)', hwFault: 'falha de hardware', open: '🌐 AxeOS', last: 'última leitura', hot: 'chip quente', vrhot: 'regulador quente', lowhash: 'hashrate baixo', onBackup: 'na pool reserva', reboots: 'reinícios', lastAct: 'Última ação', acts: { restart: 'reiniciar', identify: 'identificar', pause: 'pausar', resume: 'retomar', fan: 'fan', point: 'apontar para o proxy' }, actFail: 'falhou', actions: 'ações ⚙️', chHash: 'Hashrate · 24 h', chTemp: 'Chip · 24 h', chWait: 'o gráfico aparece depois de 10 min de leituras' };
// Gráficos de 24 h do Bitaxe: dois pequenos lado a lado (hashrate e chip), cada um com o seu eixo, nunca dois eixos no mesmo
const BXCH = {}; // id do gráfico → pontos, para o tooltip
function bxChart(id, title, pts, fmt) {
Expand Down Expand Up @@ -1838,7 +1840,8 @@ function renderBitaxes(j) {
const st = (label, val) => '<div><span>' + label + '</span>' + val + '</div>';
$('bxlist').innerHTML = list.map((b) => {
const d = b.data;
const link = /^[\w.:\-]+$/.test(b.host) ? '<a href="http://' + esc(b.host) + '/" target="_blank" rel="noopener noreferrer">' + BXT.open + '</a>' : '';
const addr = (d && d.ip) || b.host; // IP primeiro: nome .local não abre em todo celular
const link = /^[\w.:\-]+$/.test(addr) ? '<a class="axeos" href="http://' + esc(addr) + '/" target="_blank" rel="noopener noreferrer">' + BXT.open + ' <span>' + esc(addr) + '</span> ↗</a>' : '';
const head = '<div class="bxh"><b>' + esc(b.name) + '</b><span class="sub">' + esc([d && d.model, d && d.version, b.host].filter(Boolean).join(' · ')) + '</span>' +
(!b.fresh ? '<span class="temp hot">' + BXT.noAnswer + (b.okAt ? ' · ' + BXT.last + ' ' + agoTxt(b.okAt) : '') + '</span>' : '') + link + '<a href="/config#miners">' + BXT.actions + '</a></div>';
if (!d) return '<div class="bx">' + head + '</div>';
Expand Down
6 changes: 6 additions & 0 deletions tests/bitaxe.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,3 +276,9 @@ test('worker do Bitaxe em SOLO Group: sem o #grupo (e sem o .hidden)', () => {
assert.strictEqual(d('bc1qx.bitaxe2#minhaturma.hidden'), 'bitaxe2');
assert.strictEqual(d('bc1qx.bitaxe3'), 'bitaxe3');
});

test('IP do AxeOS para o link (ipv4 válido; senão nada)', () => {
assert.strictEqual(bx.normalize({ ipv4: '192.168.0.138' }).ip, '192.168.0.138');
assert.strictEqual(bx.normalize({ ipv4: '<script>' }).ip, null);
assert.strictEqual(bx.normalize({}).ip, null);
});
Loading