-
-
+
+
+
-
-
-
You must restart this device after saving for changes to take effect.
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
-
+
+
+
+
-
-
Update Firmware {{firmwareUpdateProgress}}%
-
-
- (esp-miner.bin)
-
-
-
Update Website {{websiteUpdateProgress}}%
-
-
- (www.bin)
-
\ No newline at end of file
+
+
+
+
+
+
+ You must restart this device after saving for changes to take effect.
+
+
+
+
+
\ No newline at end of file
diff --git a/main/http_server/axe-os/src/app/components/edit/edit.component.ts b/main/http_server/axe-os/src/app/components/edit/edit.component.ts
index 6610cc98..8b04f175 100644
--- a/main/http_server/axe-os/src/app/components/edit/edit.component.ts
+++ b/main/http_server/axe-os/src/app/components/edit/edit.component.ts
@@ -1,4 +1,4 @@
-import { HttpErrorResponse, HttpEventType } from '@angular/common/http';
+import { HttpErrorResponse } from '@angular/common/http';
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ToastrService } from 'ngx-toastr';
@@ -111,81 +111,4 @@ export class EditComponent {
});
}
- otaUpdate(event: any) {
- const file = event.target?.files.item(0) as File;
-
- if (file.name != 'esp-miner.bin') {
- this.toastrService.error('Incorrect file, looking for esp-miner.bin.', 'Error');
- return;
- }
-
- this.systemService.performOTAUpdate(file)
- .pipe(this.loadingService.lockUIUntilComplete())
- .subscribe({
- next: (event) => {
- if (event.type === HttpEventType.UploadProgress) {
- this.firmwareUpdateProgress = Math.round((event.loaded / (event.total as number)) * 100);
- } else if (event.type === HttpEventType.Response) {
- if (event.ok) {
- this.toastrService.success('Firmware updated', 'Success!');
-
- } else {
- this.toastrService.error(event.statusText, 'Error');
- }
- }
- },
- error: (err) => {
- this.toastrService.error(event.statusText, 'Error');
- },
- complete: () => {
- this.firmwareUpdateProgress = null;
- }
- });
- }
- otaWWWUpdate(event: any) {
- const file = event.target?.files.item(0) as File;
- if (file.name != 'www.bin') {
- this.toastrService.error('Incorrect file, looking for www.bin.', 'Error');
- return;
- }
-
- this.systemService.performWWWOTAUpdate(file)
- .pipe(
- this.loadingService.lockUIUntilComplete(),
- ).subscribe({
- next: (event) => {
- if (event.type === HttpEventType.UploadProgress) {
- this.websiteUpdateProgress = Math.round((event.loaded / (event.total as number)) * 100);
- } else if (event.type === HttpEventType.Response) {
- if (event.ok) {
- setTimeout(() => {
- this.toastrService.success('Website updated', 'Success!');
- window.location.reload();
- }, 1000);
-
- } else {
- this.toastrService.error(event.statusText, 'Error');
- }
- }
- },
- error: (err) => {
- this.toastrService.error(event.statusText, 'Error');
- },
- complete: () => {
- this.websiteUpdateProgress = null;
- }
- });
- }
-
- public restart() {
- this.systemService.restart().subscribe(res => {
-
- });
- this.toastr.success('Success!', 'Bitaxe restarted');
- }
-
-
-
-
-
}
diff --git a/main/http_server/axe-os/src/app/components/settings/settings.component.html b/main/http_server/axe-os/src/app/components/settings/settings.component.html
new file mode 100644
index 00000000..8311164b
--- /dev/null
+++ b/main/http_server/axe-os/src/app/components/settings/settings.component.html
@@ -0,0 +1,21 @@
+
+
+
+
Update Firmware {{firmwareUpdateProgress}}%
+
+
+ (esp-miner.bin)
+
+
+
+
Update Website {{websiteUpdateProgress}}%
+
+
+ (www.bin)
+
\ No newline at end of file
diff --git a/main/http_server/axe-os/src/app/components/settings/settings.component.scss b/main/http_server/axe-os/src/app/components/settings/settings.component.scss
new file mode 100644
index 00000000..aeb89d19
--- /dev/null
+++ b/main/http_server/axe-os/src/app/components/settings/settings.component.scss
@@ -0,0 +1,31 @@
+input[type="text"],
+input[type="number"],
+input[type="password"],
+input[type="range"] {
+ min-width: 250px;
+ max-width: 90%;
+}
+
+select {
+ min-width: 268px;
+ max-width: 90%;
+}
+
+.restart {
+ margin-bottom: 1.5rem;
+
+}
+
+@media only screen and (min-width:900px) {
+
+ input[type="text"],
+ input[type="password"],
+ input[type="number"],
+ input[type="range"] {
+ min-width: 500px
+ }
+
+ select {
+ min-width: 518px
+ }
+}
\ No newline at end of file
diff --git a/main/http_server/axe-os/src/app/components/settings/settings.component.spec.ts b/main/http_server/axe-os/src/app/components/settings/settings.component.spec.ts
new file mode 100644
index 00000000..c2333ad2
--- /dev/null
+++ b/main/http_server/axe-os/src/app/components/settings/settings.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SettingsComponent } from './settings.component';
+
+describe('SettingsComponent', () => {
+ let component: SettingsComponent;
+ let fixture: ComponentFixture
;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ declarations: [SettingsComponent]
+ });
+ fixture = TestBed.createComponent(SettingsComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/main/http_server/axe-os/src/app/components/settings/settings.component.ts b/main/http_server/axe-os/src/app/components/settings/settings.component.ts
new file mode 100644
index 00000000..04b71d8e
--- /dev/null
+++ b/main/http_server/axe-os/src/app/components/settings/settings.component.ts
@@ -0,0 +1,191 @@
+import { HttpErrorResponse, HttpEventType } from '@angular/common/http';
+import { Component } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { ToastrService } from 'ngx-toastr';
+import { startWith } from 'rxjs';
+import { LoadingService } from 'src/app/services/loading.service';
+import { SystemService } from 'src/app/services/system.service';
+import { eASICModel } from 'src/models/enum/eASICModel';
+
+@Component({
+ selector: 'app-settings',
+ templateUrl: './settings.component.html',
+ styleUrls: ['./settings.component.scss']
+})
+export class SettingsComponent {
+
+ public form!: FormGroup;
+
+ public firmwareUpdateProgress: number | null = null;
+ public websiteUpdateProgress: number | null = null;
+
+
+ public devToolsOpen: boolean = false;
+ public eASICModel = eASICModel;
+ public ASICModel!: eASICModel;
+
+ constructor(
+ private fb: FormBuilder,
+ private systemService: SystemService,
+ private toastr: ToastrService,
+ private toastrService: ToastrService,
+ private loadingService: LoadingService
+ ) {
+
+ window.addEventListener('resize', this.checkDevTools);
+ this.checkDevTools();
+
+ this.systemService.getInfo()
+ .pipe(this.loadingService.lockUIUntilComplete())
+ .subscribe(info => {
+ this.ASICModel = info.ASICModel;
+ this.form = this.fb.group({
+ flipscreen: [info.flipscreen == 1],
+ invertscreen: [info.invertscreen == 1],
+ stratumURL: [info.stratumURL, [
+ Validators.required,
+ Validators.pattern(/^(?!.*stratum\+tcp:\/\/).*$/),
+ Validators.pattern(/^[^:]*$/),
+ ]],
+ stratumPort: [info.stratumPort, [
+ Validators.required,
+ Validators.pattern(/^[^:]*$/),
+ Validators.min(0),
+ Validators.max(65353)
+ ]],
+ stratumUser: [info.stratumUser, [Validators.required]],
+ ssid: [info.ssid, [Validators.required]],
+ wifiPass: [info.wifiPass, [Validators.required]],
+ coreVoltage: [info.coreVoltage, [Validators.required]],
+ frequency: [info.frequency, [Validators.required]],
+ autofanspeed: [info.autofanspeed == 1, [Validators.required]],
+ invertfanpolarity: [info.invertfanpolarity == 1, [Validators.required]],
+ fanspeed: [info.fanspeed, [Validators.required]],
+ });
+
+ this.form.controls['autofanspeed'].valueChanges.pipe(
+ startWith(this.form.controls['autofanspeed'].value)
+ ).subscribe(autofanspeed => {
+ if (autofanspeed) {
+ this.form.controls['fanspeed'].disable();
+ } else {
+ this.form.controls['fanspeed'].enable();
+ }
+ });
+ });
+
+ }
+ private checkDevTools = () => {
+ if (
+ window.outerWidth - window.innerWidth > 160 ||
+ window.outerHeight - window.innerHeight > 160
+ ) {
+ this.devToolsOpen = true;
+ } else {
+ this.devToolsOpen = false;
+ }
+ };
+
+ public updateSystem() {
+
+ const form = this.form.getRawValue();
+
+ form.frequency = parseInt(form.frequency);
+ form.coreVoltage = parseInt(form.coreVoltage);
+
+ // bools to ints
+ form.flipscreen = form.flipscreen == true ? 1 : 0;
+ form.invertscreen = form.invertscreen == true ? 1 : 0;
+ form.invertfanpolarity = form.invertfanpolarity == true ? 1 : 0;
+ form.autofanspeed = form.autofanspeed == true ? 1 : 0;
+
+ this.systemService.updateSystem(form)
+ .pipe(this.loadingService.lockUIUntilComplete())
+ .subscribe({
+ next: () => {
+ this.toastr.success('Success!', 'Saved.');
+ },
+ error: (err: HttpErrorResponse) => {
+ this.toastr.error('Error.', `Could not save. ${err.message}`);
+ }
+ });
+ }
+
+ otaUpdate(event: any) {
+ const file = event.target?.files.item(0) as File;
+
+ if (file.name != 'esp-miner.bin') {
+ this.toastrService.error('Incorrect file, looking for esp-miner.bin.', 'Error');
+ return;
+ }
+
+ this.systemService.performOTAUpdate(file)
+ .pipe(this.loadingService.lockUIUntilComplete())
+ .subscribe({
+ next: (event) => {
+ if (event.type === HttpEventType.UploadProgress) {
+ this.firmwareUpdateProgress = Math.round((event.loaded / (event.total as number)) * 100);
+ } else if (event.type === HttpEventType.Response) {
+ if (event.ok) {
+ this.toastrService.success('Firmware updated', 'Success!');
+
+ } else {
+ this.toastrService.error(event.statusText, 'Error');
+ }
+ }
+ },
+ error: (err) => {
+ this.toastrService.error(event.statusText, 'Error');
+ },
+ complete: () => {
+ this.firmwareUpdateProgress = null;
+ }
+ });
+ }
+ otaWWWUpdate(event: any) {
+ const file = event.target?.files.item(0) as File;
+ if (file.name != 'www.bin') {
+ this.toastrService.error('Incorrect file, looking for www.bin.', 'Error');
+ return;
+ }
+
+ this.systemService.performWWWOTAUpdate(file)
+ .pipe(
+ this.loadingService.lockUIUntilComplete(),
+ ).subscribe({
+ next: (event) => {
+ if (event.type === HttpEventType.UploadProgress) {
+ this.websiteUpdateProgress = Math.round((event.loaded / (event.total as number)) * 100);
+ } else if (event.type === HttpEventType.Response) {
+ if (event.ok) {
+ setTimeout(() => {
+ this.toastrService.success('Website updated', 'Success!');
+ window.location.reload();
+ }, 1000);
+
+ } else {
+ this.toastrService.error(event.statusText, 'Error');
+ }
+ }
+ },
+ error: (err) => {
+ this.toastrService.error(event.statusText, 'Error');
+ },
+ complete: () => {
+ this.websiteUpdateProgress = null;
+ }
+ });
+ }
+
+ public restart() {
+ this.systemService.restart().subscribe(res => {
+
+ });
+ this.toastr.success('Success!', 'Bitaxe restarted');
+ }
+
+
+
+
+
+}
diff --git a/main/http_server/axe-os/src/app/components/swarm/swarm.component.html b/main/http_server/axe-os/src/app/components/swarm/swarm.component.html
index 9242baab..cf003e35 100644
--- a/main/http_server/axe-os/src/app/components/swarm/swarm.component.html
+++ b/main/http_server/axe-os/src/app/components/swarm/swarm.component.html
@@ -3,6 +3,9 @@
+
+
+
@@ -13,18 +16,22 @@
Power |
Temp |
Best Difficulty |
+ Edit |
+ Restart |
Remove |
- {{axe.ip}} |
+ {{axe.ip}} |
{{axe.hashRate | number: '1.2-2'}} Gh/s |
{{axe.uptimeSeconds | dateAgo}} |
{{axe.sharesAccepted}} |
{{axe.power | number: '1.2-2'}} W |
{{axe.temp}} C |
{{axe.bestDiff}} |
- |
+ |
+ |
+ |
diff --git a/main/http_server/axe-os/src/app/components/swarm/swarm.component.scss b/main/http_server/axe-os/src/app/components/swarm/swarm.component.scss
index 2f9eb2bf..ab66c8d5 100644
--- a/main/http_server/axe-os/src/app/components/swarm/swarm.component.scss
+++ b/main/http_server/axe-os/src/app/components/swarm/swarm.component.scss
@@ -19,4 +19,8 @@ th,
td {
padding: 1rem 1rem;
border-bottom: 1px solid #304562;
+}
+
+a {
+ color: white;
}
\ No newline at end of file
diff --git a/main/http_server/axe-os/src/app/components/swarm/swarm.component.ts b/main/http_server/axe-os/src/app/components/swarm/swarm.component.ts
index 882d6498..e1427f71 100644
--- a/main/http_server/axe-os/src/app/components/swarm/swarm.component.ts
+++ b/main/http_server/axe-os/src/app/components/swarm/swarm.component.ts
@@ -1,7 +1,7 @@
import { Component } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { ToastrService } from 'ngx-toastr';
-import { catchError, map, Observable, of, startWith, switchMap } from 'rxjs';
+import { BehaviorSubject, catchError, map, Observable, of, startWith, switchMap } from 'rxjs';
import { SystemService } from 'src/app/services/system.service';
@Component({
@@ -15,6 +15,8 @@ export class SwarmComponent {
public swarm$: Observable
[]>;
+ public refresh$: BehaviorSubject = new BehaviorSubject(null);
+
constructor(
private fb: FormBuilder,
private systemService: SystemService,
@@ -28,7 +30,11 @@ export class SwarmComponent {
map(swarmInfo => {
return swarmInfo.map(({ ip }) => {
// Make individual API calls for each IP
- return this.systemService.getInfo(`http://${ip}`).pipe(
+ return this.refresh$.pipe(
+ switchMap(() => {
+ return this.systemService.getInfo(`http://${ip}`);
+ })
+ ).pipe(
startWith({ ip }),
map(info => {
return {
@@ -70,6 +76,20 @@ export class SwarmComponent {
}
+ public refresh() {
+ this.refresh$.next(null);
+ }
+
+ public edit(axe: any) {
+
+ }
+ public restart(axe: any) {
+ this.systemService.restart(`http://${axe.ip}`).subscribe(res => {
+
+ });
+ this.toastr.success('Success!', 'Bitaxe restarted');
+ }
+
public remove(axe: any) {
this.systemService.getSwarmInfo().pipe(
switchMap((swarm: any) => {
diff --git a/main/http_server/axe-os/src/app/services/system.service.ts b/main/http_server/axe-os/src/app/services/system.service.ts
index d95f09e3..2cd07bc5 100644
--- a/main/http_server/axe-os/src/app/services/system.service.ts
+++ b/main/http_server/axe-os/src/app/services/system.service.ts
@@ -15,9 +15,9 @@ export class SystemService {
private httpClient: HttpClient
) { }
- public getInfo(ip: string = ''): Observable {
+ public getInfo(uri: string = ''): Observable {
if (environment.production) {
- return this.httpClient.get(`${ip}/api/system/info`) as Observable;
+ return this.httpClient.get(`${uri}/api/system/info`) as Observable;
} else {
return of(
{
@@ -53,8 +53,8 @@ export class SystemService {
}
}
- public restart() {
- return this.httpClient.post(`/api/system/restart`, {});
+ public restart(uri: string = '') {
+ return this.httpClient.post(`${uri}/api/system/restart`, {});
}
public updateSystem(update: any) {