Skip to content
Open
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
1 change: 1 addition & 0 deletions main/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ SRCS
"./power/INA260.c"
"./power/power.c"
"./power/vcore.c"
"mining_controller.c"

INCLUDE_DIRS
"."
Expand Down
10 changes: 10 additions & 0 deletions main/global_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include "stratum_api.h"
#include "work_queue.h"
#include "device_config.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "display.h"

#define STRATUM_USER CONFIG_STRATUM_USER
Expand Down Expand Up @@ -108,6 +110,14 @@ typedef struct

bool ASIC_initalized;
bool psram_is_available;

bool mining_enabled;
TaskHandle_t power_management_task_handle;
TaskHandle_t stratum_task_handle;
TaskHandle_t stratum_primary_heartbeat_task_handle;
TaskHandle_t create_jobs_task_handle;
TaskHandle_t asic_task_handle;
TaskHandle_t asic_result_task_handle;
} GlobalState;

#endif /* GLOBAL_STATE_H_ */
5 changes: 1 addition & 4 deletions main/http_server/axe-os/api/system/asic_settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@
#include "cJSON.h"
#include "global_state.h"
#include "asic.h"
#include "http_server.h"

// static const char *TAG = "asic_api";
static GlobalState *GLOBAL_STATE = NULL;

// Function declarations from http_server.c
extern esp_err_t is_network_allowed(httpd_req_t *req);
extern esp_err_t set_cors_headers(httpd_req_t *req);

// Initialize the ASIC API with the global state
void asic_api_init(GlobalState *global_state) {
GLOBAL_STATE = global_state;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
<h4>Loading...</h4>
</ng-template>
<ng-container *ngIf="info$ | async as info; else loading">
<p-message *ngIf="!info.miningEnabled" severity="info" styleClass="w-full mb-4 py-4 border-round-xl"
text="Mining manually disabled. Enable mining to start hashing again.">
</p-message>

<!-- Temp warning alert -->
<p-message *ngIf="info.overheat_mode" severity="error" styleClass="w-full mb-4 py-4 border-round-xl"
text="Bitaxe has overheated - See settings">
Expand Down Expand Up @@ -279,5 +283,13 @@ <h5>Uptime</h5>
</div>
</div>

<div class="col-12 lg:col-6">
<div class="card">
<h5>Mining Status</h5>
<p>Mining is currently {{ info.miningEnabled ? 'Enabled' : 'Disabled' }}.</p>
<button pButton type="button" icon="{{info.miningEnabled ? 'pi pi-stop-circle' : 'pi pi-play'}}" label="{{info.miningEnabled ? 'Disable Mining' : 'Enable Mining'}}" (click)="toggleMining(info.miningEnabled)"></button>
</div>
</div>

</div>
</ng-container>
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Component } from '@angular/core';
import { ToastrService } from 'ngx-toastr';
import { interval, map, Observable, shareReplay, startWith, switchMap, tap } from 'rxjs';
import { HashSuffixPipe } from 'src/app/pipes/hash-suffix.pipe';
import { QuicklinkService } from 'src/app/services/quicklink.service';
Expand Down Expand Up @@ -47,7 +48,8 @@ export class HomeComponent {
private systemService: SystemService,
private themeService: ThemeService,
private quickLinkService: QuicklinkService,
private shareRejectReasonsService: ShareRejectionExplanationService
private shareRejectReasonsService: ShareRejectionExplanationService,
private toastr: ToastrService
) {
this.initializeChart();

Expand Down Expand Up @@ -304,6 +306,21 @@ export class HomeComponent {
return item.message; //Track only by message
}

toggleMining(miningEnabled: boolean) {
this.toastr.info(`Toggling mining ${miningEnabled ? 'off' : 'on'}`, 'Requested');
const miningAction = miningEnabled ? this.systemService.stopMining() : this.systemService.startMining();

miningAction.subscribe({
next: () => {
this.toastr.success(`Mining ${miningEnabled ? 'disabled' : 'enabled'}`, 'Success')
},
error: (err) => {

this.toastr.error(`Failed to toggle mining: ${err}`, 'Error')
}
});
}

public calculateAverage(data: number[]): number {
if (data.length === 0) return 0;
const sum = data.reduce((sum, value) => sum + value, 0);
Expand Down
12 changes: 10 additions & 2 deletions main/http_server/axe-os/src/app/services/system.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ export class SystemService {
statsLimit: 360,
statsDuration: 2,
fanrpm: 0,

boardtemp1: 30,
boardtemp2: 40,
overheat_mode: 0
overheat_mode: 0,
miningEnabled: true
}
).pipe(delay(1000));
}
Expand Down Expand Up @@ -103,6 +103,14 @@ export class SystemService {
}).pipe(delay(1000));
}

public startMining(uri: string = ''): Observable<any> {
return this.httpClient.patch(`${uri}/api/mining/start`, {});
}

public stopMining(uri: string = ''): Observable<any> {
return this.httpClient.patch(`${uri}/api/mining/stop`, {});
}

public restart(uri: string = '') {
return this.httpClient.post(`${uri}/api/system/restart`, {}, {responseType: 'text'});
}
Expand Down
1 change: 1 addition & 0 deletions main/http_server/axe-os/src/models/ISystemInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,5 @@ export interface ISystemInfo {
overheat_mode: number,
power_fault?: string
overclockEnabled?: number
miningEnabled: boolean;
}
94 changes: 94 additions & 0 deletions main/http_server/http_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "statistics_task.h"
#include "theme_api.h" // Add theme API include
#include "axe-os/api/system/asic_settings.h"
#include "mining_controller.h"
#include "http_server.h"

#define JSON_ALL_STATS_ELEMENT_SIZE 120
Expand Down Expand Up @@ -618,6 +619,7 @@ static esp_err_t GET_system_info(httpd_req_t * req)
cJSON_AddStringToObject(root, "idfVersion", esp_get_idf_version());
cJSON_AddStringToObject(root, "boardVersion", GLOBAL_STATE->DEVICE_CONFIG.board_version);
cJSON_AddStringToObject(root, "runningPartition", esp_ota_get_running_partition()->label);
cJSON_AddBoolToObject(root, "miningEnabled", GLOBAL_STATE->mining_enabled);

cJSON_AddNumberToObject(root, "overheat_mode", nvs_config_get_u16(NVS_CONFIG_OVERHEAT_MODE, 0));
cJSON_AddNumberToObject(root, "overclockEnabled", nvs_config_get_u16(NVS_CONFIG_OVERCLOCK_ENABLED, 0));
Expand Down Expand Up @@ -933,6 +935,66 @@ esp_err_t POST_OTA_update(httpd_req_t * req)
return ESP_OK;
}

static esp_err_t PATCH_mining_stop_handler(httpd_req_t *req)
{
if (is_network_allowed(req) != ESP_OK) {
return httpd_resp_send_err(req, HTTPD_401_UNAUTHORIZED, "Unauthorized");
}
if (set_cors_headers(req) != ESP_OK) {
httpd_resp_send_500(req);
return ESP_OK;
}

ESP_LOGI(TAG, "API call to stop mining.");
esp_err_t err = stop_mining(GLOBAL_STATE);

httpd_resp_set_type(req, "application/json");
cJSON *root = cJSON_CreateObject();
if (err == ESP_OK) {
cJSON_AddStringToObject(root, "status", "ok");
cJSON_AddStringToObject(root, "message", "Mining stop requested successfully.");
} else {
cJSON_AddStringToObject(root, "status", "error");
cJSON_AddStringToObject(root, "message", "Failed to request mining stop.");
httpd_resp_set_status(req, HTTPD_500_INTERNAL_SERVER_ERROR);
}
const char *response = cJSON_Print(root);
httpd_resp_sendstr(req, response);
free((void *)response);
cJSON_Delete(root);
return ESP_OK;
}

static esp_err_t PATCH_mining_start_handler(httpd_req_t *req)
{
if (is_network_allowed(req) != ESP_OK) {
return httpd_resp_send_err(req, HTTPD_401_UNAUTHORIZED, "Unauthorized");
}
if (set_cors_headers(req) != ESP_OK) {
httpd_resp_send_500(req);
return ESP_OK;
}

ESP_LOGI(TAG, "API call to start mining.");
esp_err_t err = start_mining(GLOBAL_STATE);

httpd_resp_set_type(req, "application/json");
cJSON *root = cJSON_CreateObject();
if (err == ESP_OK) {
cJSON_AddStringToObject(root, "status", "ok");
cJSON_AddStringToObject(root, "message", "Mining start requested successfully.");
} else {
cJSON_AddStringToObject(root, "status", "error");
cJSON_AddStringToObject(root, "message", "Failed to request mining start.");
httpd_resp_set_status(req, HTTPD_500_INTERNAL_SERVER_ERROR);
}
const char *response = cJSON_Print(root);
httpd_resp_sendstr(req, response);
free((void *)response);
cJSON_Delete(root);
return ESP_OK;
}

int log_to_queue(const char * format, va_list args)
{
va_list args_copy;
Expand Down Expand Up @@ -1201,6 +1263,38 @@ esp_err_t start_rest_server(void * pvParameters)
};
httpd_register_uri_handler(server, &ws);

httpd_uri_t mining_stop_uri = {
.uri = "/api/mining/stop",
.method = HTTP_PATCH,
.handler = PATCH_mining_stop_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &mining_stop_uri);

httpd_uri_t mining_stop_options_uri = {
.uri = "/api/mining/stop",
.method = HTTP_OPTIONS,
.handler = handle_options_request,
.user_ctx = NULL
};
httpd_register_uri_handler(server, &mining_stop_options_uri);

httpd_uri_t mining_start_uri = {
.uri = "/api/mining/start",
.method = HTTP_PATCH,
.handler = PATCH_mining_start_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &mining_start_uri);

httpd_uri_t mining_start_options_uri = {
.uri = "/api/mining/start",
.method = HTTP_OPTIONS,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not that familiar with the AxeOS api, so maybe a silly question, why does this need both an OPTIONS as well as a PATCH handler? Why is this not just a POST?

.handler = handle_options_request,
.user_ctx = NULL
};
httpd_register_uri_handler(server, &mining_start_options_uri);

if (enter_recovery) {
/* Make default route serve Recovery */
httpd_uri_t recovery_implicit_get_uri = {
Expand Down
3 changes: 3 additions & 0 deletions main/http_server/http_server.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#ifndef HTTP_SERVER_H_
#define HTTP_SERVER_H_
#include <esp_http_server.h>
#include "esp_err.h"

esp_err_t start_rest_server(void *pvParameters);
esp_err_t is_network_allowed(httpd_req_t *req);
esp_err_t set_cors_headers(httpd_req_t *req);

#endif
64 changes: 64 additions & 0 deletions main/http_server/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ components:
- displayTimeout
- statisticsLimit
- statisticsDuration
- miningEnabled
properties:
ASICModel:
type: string
Expand Down Expand Up @@ -298,6 +299,9 @@ components:
statsDuration:
type: number
description: Statistics duration in hours
miningEnabled:
type: boolean
description: Whether mining is currently enabled (true) or stopped (false)

Settings:
type: object
Expand Down Expand Up @@ -454,8 +458,68 @@ components:

InternalError:
description: Internal server error
MiningActionResponse:
type: object
properties:
status:
type: string
enum: [ok, error]
description: Result status of the action.
message:
type: string
description: A message describing the result of the action.
required:
- status
- message

paths:
/api/mining/start:
patch:
summary: Start mining operations
description: Initiates or restarts the mining process.
operationId: startMining
tags:
- mining
responses:
'200':
description: Mining start successfully requested.
content:
application/json:
schema:
$ref: '#/components/schemas/MiningActionResponse'
'401':
$ref: '#/components/responses/UnauthorizedError'
'500':
$ref: '#/components/responses/InternalError'
content:
application/json:
schema:
$ref: '#/components/schemas/MiningActionResponse'


/api/mining/stop:
patch:
summary: Stop mining operations
description: Halts the current mining process.
operationId: stopMining
tags:
- mining
responses:
'200':
description: Mining stop successfully requested.
content:
application/json:
schema:
$ref: '#/components/schemas/MiningActionResponse'
'401':
$ref: '#/components/responses/UnauthorizedError'
'500':
$ref: '#/components/responses/InternalError'
content:
application/json:
schema:
$ref: '#/components/schemas/MiningActionResponse'

/api/system/wifi/scan:
get:
summary: Scan for available WiFi networks
Expand Down
Loading
Loading