Add LED ring control per client and broadcast over REST and WebSocket.
Solid color mode fills all ring LEDs; master routes UART commands to slaves via ESPNOW_LED_RING. goTool exposes POST /api/led-ring, WebSocket set_led_ring, and a dashboard LED panel with master/slave/all targets. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -30,6 +30,9 @@ PB_BIND(alox_EspNowAccelStream, alox_EspNowAccelStream, AUTO)
|
||||
PB_BIND(alox_EspNowAccelSample, alox_EspNowAccelSample, AUTO)
|
||||
|
||||
|
||||
PB_BIND(alox_EspNowLedRing, alox_EspNowLedRing, AUTO)
|
||||
|
||||
|
||||
PB_BIND(alox_EspNowOtaStart, alox_EspNowOtaStart, AUTO)
|
||||
|
||||
|
||||
|
||||
@@ -24,7 +24,8 @@ typedef enum _alox_EspNowMessageType {
|
||||
alox_EspNowMessageType_ESPNOW_FIND_ME = 10,
|
||||
alox_EspNowMessageType_ESPNOW_RESTART = 11,
|
||||
alox_EspNowMessageType_ESPNOW_ACCEL_SAMPLE = 12,
|
||||
alox_EspNowMessageType_ESPNOW_SET_ACCEL_STREAM = 13
|
||||
alox_EspNowMessageType_ESPNOW_SET_ACCEL_STREAM = 13,
|
||||
alox_EspNowMessageType_ESPNOW_LED_RING = 14
|
||||
} alox_EspNowMessageType;
|
||||
|
||||
/* Struct definitions */
|
||||
@@ -75,6 +76,20 @@ typedef struct _alox_EspNowAccelSample {
|
||||
int32_t z;
|
||||
} alox_EspNowAccelSample;
|
||||
|
||||
/* * Master → slave: LED ring command (same modes as UART LedRingProgressRequest). */
|
||||
typedef struct _alox_EspNowLedRing {
|
||||
uint32_t client_id;
|
||||
uint32_t mode;
|
||||
uint32_t progress;
|
||||
uint32_t digit;
|
||||
uint32_t r;
|
||||
uint32_t g;
|
||||
uint32_t b;
|
||||
uint32_t intensity;
|
||||
uint32_t blink_ms;
|
||||
uint32_t blink_count;
|
||||
} alox_EspNowLedRing;
|
||||
|
||||
/* Master → slave: begin OTA (erase inactive slot; slave replies ESPNOW_OTA_STATUS). */
|
||||
typedef struct _alox_EspNowOtaStart {
|
||||
uint32_t total_size;
|
||||
@@ -116,6 +131,7 @@ typedef struct _alox_EspNowMessage {
|
||||
alox_EspNowRestart restart;
|
||||
alox_EspNowAccelSample accel_sample;
|
||||
alox_EspNowAccelStream accel_stream;
|
||||
alox_EspNowLedRing led_ring;
|
||||
} payload;
|
||||
} alox_EspNowMessage;
|
||||
|
||||
@@ -126,8 +142,9 @@ extern "C" {
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _alox_EspNowMessageType_MIN alox_EspNowMessageType_ESPNOW_UNKNOWN
|
||||
#define _alox_EspNowMessageType_MAX alox_EspNowMessageType_ESPNOW_SET_ACCEL_STREAM
|
||||
#define _alox_EspNowMessageType_ARRAYSIZE ((alox_EspNowMessageType)(alox_EspNowMessageType_ESPNOW_SET_ACCEL_STREAM+1))
|
||||
#define _alox_EspNowMessageType_MAX alox_EspNowMessageType_ESPNOW_LED_RING
|
||||
#define _alox_EspNowMessageType_ARRAYSIZE ((alox_EspNowMessageType)(alox_EspNowMessageType_ESPNOW_LED_RING+1))
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -153,6 +170,7 @@ extern "C" {
|
||||
#define alox_EspNowAccelDeadzone_init_default {0, 0}
|
||||
#define alox_EspNowAccelStream_init_default {0, 0}
|
||||
#define alox_EspNowAccelSample_init_default {0, 0, 0, 0}
|
||||
#define alox_EspNowLedRing_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define alox_EspNowOtaStart_init_default {0}
|
||||
#define alox_EspNowOtaPayload_init_default {0, {0, {0}}}
|
||||
#define alox_EspNowOtaEnd_init_default {0}
|
||||
@@ -166,6 +184,7 @@ extern "C" {
|
||||
#define alox_EspNowAccelDeadzone_init_zero {0, 0}
|
||||
#define alox_EspNowAccelStream_init_zero {0, 0}
|
||||
#define alox_EspNowAccelSample_init_zero {0, 0, 0, 0}
|
||||
#define alox_EspNowLedRing_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define alox_EspNowOtaStart_init_zero {0}
|
||||
#define alox_EspNowOtaPayload_init_zero {0, {0, {0}}}
|
||||
#define alox_EspNowOtaEnd_init_zero {0}
|
||||
@@ -191,6 +210,16 @@ extern "C" {
|
||||
#define alox_EspNowAccelSample_x_tag 2
|
||||
#define alox_EspNowAccelSample_y_tag 3
|
||||
#define alox_EspNowAccelSample_z_tag 4
|
||||
#define alox_EspNowLedRing_client_id_tag 1
|
||||
#define alox_EspNowLedRing_mode_tag 2
|
||||
#define alox_EspNowLedRing_progress_tag 3
|
||||
#define alox_EspNowLedRing_digit_tag 4
|
||||
#define alox_EspNowLedRing_r_tag 5
|
||||
#define alox_EspNowLedRing_g_tag 6
|
||||
#define alox_EspNowLedRing_b_tag 7
|
||||
#define alox_EspNowLedRing_intensity_tag 8
|
||||
#define alox_EspNowLedRing_blink_ms_tag 9
|
||||
#define alox_EspNowLedRing_blink_count_tag 10
|
||||
#define alox_EspNowOtaStart_total_size_tag 1
|
||||
#define alox_EspNowOtaPayload_seq_tag 1
|
||||
#define alox_EspNowOtaPayload_data_tag 2
|
||||
@@ -211,6 +240,7 @@ extern "C" {
|
||||
#define alox_EspNowMessage_restart_tag 12
|
||||
#define alox_EspNowMessage_accel_sample_tag 13
|
||||
#define alox_EspNowMessage_accel_stream_tag 14
|
||||
#define alox_EspNowMessage_led_ring_tag 15
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define alox_EspNowUnicastTest_FIELDLIST(X, a) \
|
||||
@@ -263,6 +293,20 @@ X(a, STATIC, SINGULAR, SINT32, z, 4)
|
||||
#define alox_EspNowAccelSample_CALLBACK NULL
|
||||
#define alox_EspNowAccelSample_DEFAULT NULL
|
||||
|
||||
#define alox_EspNowLedRing_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, client_id, 1) \
|
||||
X(a, STATIC, SINGULAR, UINT32, mode, 2) \
|
||||
X(a, STATIC, SINGULAR, UINT32, progress, 3) \
|
||||
X(a, STATIC, SINGULAR, UINT32, digit, 4) \
|
||||
X(a, STATIC, SINGULAR, UINT32, r, 5) \
|
||||
X(a, STATIC, SINGULAR, UINT32, g, 6) \
|
||||
X(a, STATIC, SINGULAR, UINT32, b, 7) \
|
||||
X(a, STATIC, SINGULAR, UINT32, intensity, 8) \
|
||||
X(a, STATIC, SINGULAR, UINT32, blink_ms, 9) \
|
||||
X(a, STATIC, SINGULAR, UINT32, blink_count, 10)
|
||||
#define alox_EspNowLedRing_CALLBACK NULL
|
||||
#define alox_EspNowLedRing_DEFAULT NULL
|
||||
|
||||
#define alox_EspNowOtaStart_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, total_size, 1)
|
||||
#define alox_EspNowOtaStart_CALLBACK NULL
|
||||
@@ -300,7 +344,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload,ota_status,payload.ota_status), 10)
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,find_me,payload.find_me), 11) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,restart,payload.restart), 12) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,accel_sample,payload.accel_sample), 13) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,accel_stream,payload.accel_stream), 14)
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,accel_stream,payload.accel_stream), 14) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,led_ring,payload.led_ring), 15)
|
||||
#define alox_EspNowMessage_CALLBACK NULL
|
||||
#define alox_EspNowMessage_DEFAULT NULL
|
||||
#define alox_EspNowMessage_payload_discover_MSGTYPE alox_EspNowDiscover
|
||||
@@ -316,6 +361,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload,accel_stream,payload.accel_stream),
|
||||
#define alox_EspNowMessage_payload_restart_MSGTYPE alox_EspNowRestart
|
||||
#define alox_EspNowMessage_payload_accel_sample_MSGTYPE alox_EspNowAccelSample
|
||||
#define alox_EspNowMessage_payload_accel_stream_MSGTYPE alox_EspNowAccelStream
|
||||
#define alox_EspNowMessage_payload_led_ring_MSGTYPE alox_EspNowLedRing
|
||||
|
||||
extern const pb_msgdesc_t alox_EspNowUnicastTest_msg;
|
||||
extern const pb_msgdesc_t alox_EspNowFindMe_msg;
|
||||
@@ -325,6 +371,7 @@ extern const pb_msgdesc_t alox_EspNowSlavePresence_msg;
|
||||
extern const pb_msgdesc_t alox_EspNowAccelDeadzone_msg;
|
||||
extern const pb_msgdesc_t alox_EspNowAccelStream_msg;
|
||||
extern const pb_msgdesc_t alox_EspNowAccelSample_msg;
|
||||
extern const pb_msgdesc_t alox_EspNowLedRing_msg;
|
||||
extern const pb_msgdesc_t alox_EspNowOtaStart_msg;
|
||||
extern const pb_msgdesc_t alox_EspNowOtaPayload_msg;
|
||||
extern const pb_msgdesc_t alox_EspNowOtaEnd_msg;
|
||||
@@ -340,6 +387,7 @@ extern const pb_msgdesc_t alox_EspNowMessage_msg;
|
||||
#define alox_EspNowAccelDeadzone_fields &alox_EspNowAccelDeadzone_msg
|
||||
#define alox_EspNowAccelStream_fields &alox_EspNowAccelStream_msg
|
||||
#define alox_EspNowAccelSample_fields &alox_EspNowAccelSample_msg
|
||||
#define alox_EspNowLedRing_fields &alox_EspNowLedRing_msg
|
||||
#define alox_EspNowOtaStart_fields &alox_EspNowOtaStart_msg
|
||||
#define alox_EspNowOtaPayload_fields &alox_EspNowOtaPayload_msg
|
||||
#define alox_EspNowOtaEnd_fields &alox_EspNowOtaEnd_msg
|
||||
@@ -355,6 +403,7 @@ extern const pb_msgdesc_t alox_EspNowMessage_msg;
|
||||
#define alox_EspNowAccelStream_size 8
|
||||
#define alox_EspNowDiscover_size 6
|
||||
#define alox_EspNowFindMe_size 6
|
||||
#define alox_EspNowLedRing_size 60
|
||||
#define alox_EspNowOtaEnd_size 0
|
||||
#define alox_EspNowOtaPayload_size 209
|
||||
#define alox_EspNowOtaStart_size 6
|
||||
|
||||
@@ -19,6 +19,7 @@ enum EspNowMessageType {
|
||||
ESPNOW_RESTART = 11;
|
||||
ESPNOW_ACCEL_SAMPLE = 12;
|
||||
ESPNOW_SET_ACCEL_STREAM = 13;
|
||||
ESPNOW_LED_RING = 14;
|
||||
}
|
||||
|
||||
message EspNowUnicastTest {
|
||||
@@ -68,6 +69,20 @@ message EspNowAccelSample {
|
||||
sint32 z = 4;
|
||||
}
|
||||
|
||||
/** Master → slave: LED ring command (same modes as UART LedRingProgressRequest). */
|
||||
message EspNowLedRing {
|
||||
uint32 client_id = 1;
|
||||
uint32 mode = 2;
|
||||
uint32 progress = 3;
|
||||
uint32 digit = 4;
|
||||
uint32 r = 5;
|
||||
uint32 g = 6;
|
||||
uint32 b = 7;
|
||||
uint32 intensity = 8;
|
||||
uint32 blink_ms = 9;
|
||||
uint32 blink_count = 10;
|
||||
}
|
||||
|
||||
// Master → slave: begin OTA (erase inactive slot; slave replies ESPNOW_OTA_STATUS).
|
||||
message EspNowOtaStart {
|
||||
uint32 total_size = 1;
|
||||
@@ -105,5 +120,6 @@ message EspNowMessage {
|
||||
EspNowRestart restart = 12;
|
||||
EspNowAccelSample accel_sample = 13;
|
||||
EspNowAccelStream accel_stream = 14;
|
||||
EspNowLedRing led_ring = 15;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,8 +139,8 @@ typedef struct _alox_EspNowUnicastTestResponse {
|
||||
uint32_t seq;
|
||||
} alox_EspNowUnicastTestResponse;
|
||||
|
||||
/* Host → device: LED ring display (progress bar, digit, clear, blink, or find-me).
|
||||
mode: 0=clear, 1=progress (0–100 %), 2=digit (0–10), 3=blink full ring, 4=find-me (R/G/B ×3 @ full brightness). */
|
||||
/* Host → master: LED ring on master (client_id=0) and/or slaves via ESP-NOW.
|
||||
mode: 0=clear, 1=progress (0–100 %), 2=digit (0–10), 3=blink, 4=find-me, 5=all LEDs solid color. */
|
||||
typedef struct _alox_LedRingProgressRequest {
|
||||
uint32_t mode;
|
||||
/* * 0–100: fraction of ring LEDs to light (mode=progress) */
|
||||
@@ -156,6 +156,12 @@ typedef struct _alox_LedRingProgressRequest {
|
||||
uint32_t blink_ms;
|
||||
/* * Number of pulses (mode=blink, default 1) */
|
||||
uint32_t blink_count;
|
||||
/* * 0 = master ring only; >0 = one slave; ignored when all_clients */
|
||||
uint32_t client_id;
|
||||
/* * Broadcast to all registered slaves (and optionally master unless slaves_only) */
|
||||
bool all_clients;
|
||||
/* * With all_clients: do not change master ring */
|
||||
bool slaves_only;
|
||||
} alox_LedRingProgressRequest;
|
||||
|
||||
typedef struct _alox_LedRingProgressResponse {
|
||||
@@ -163,6 +169,8 @@ typedef struct _alox_LedRingProgressResponse {
|
||||
uint32_t mode;
|
||||
uint32_t progress;
|
||||
uint32_t digit;
|
||||
uint32_t client_id;
|
||||
uint32_t slaves_updated;
|
||||
} alox_LedRingProgressResponse;
|
||||
|
||||
/* * Host → master: find-me on local ring (client_id=0) or ESP-NOW unicast to one slave. */
|
||||
@@ -326,8 +334,8 @@ extern "C" {
|
||||
#define alox_AccelSnapshotResponse_init_default {0, {alox_AccelSample_init_default, alox_AccelSample_init_default, alox_AccelSample_init_default, alox_AccelSample_init_default, alox_AccelSample_init_default, alox_AccelSample_init_default, alox_AccelSample_init_default, alox_AccelSample_init_default, alox_AccelSample_init_default, alox_AccelSample_init_default, alox_AccelSample_init_default, alox_AccelSample_init_default, alox_AccelSample_init_default, alox_AccelSample_init_default, alox_AccelSample_init_default, alox_AccelSample_init_default}}
|
||||
#define alox_EspNowUnicastTestRequest_init_default {0, 0}
|
||||
#define alox_EspNowUnicastTestResponse_init_default {0, 0}
|
||||
#define alox_LedRingProgressRequest_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define alox_LedRingProgressResponse_init_default {0, 0, 0, 0}
|
||||
#define alox_LedRingProgressRequest_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define alox_LedRingProgressResponse_init_default {0, 0, 0, 0, 0, 0}
|
||||
#define alox_EspNowFindMeRequest_init_default {0}
|
||||
#define alox_EspNowFindMeResponse_init_default {0, 0}
|
||||
#define alox_RestartRequest_init_default {0}
|
||||
@@ -356,8 +364,8 @@ extern "C" {
|
||||
#define alox_AccelSnapshotResponse_init_zero {0, {alox_AccelSample_init_zero, alox_AccelSample_init_zero, alox_AccelSample_init_zero, alox_AccelSample_init_zero, alox_AccelSample_init_zero, alox_AccelSample_init_zero, alox_AccelSample_init_zero, alox_AccelSample_init_zero, alox_AccelSample_init_zero, alox_AccelSample_init_zero, alox_AccelSample_init_zero, alox_AccelSample_init_zero, alox_AccelSample_init_zero, alox_AccelSample_init_zero, alox_AccelSample_init_zero, alox_AccelSample_init_zero}}
|
||||
#define alox_EspNowUnicastTestRequest_init_zero {0, 0}
|
||||
#define alox_EspNowUnicastTestResponse_init_zero {0, 0}
|
||||
#define alox_LedRingProgressRequest_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define alox_LedRingProgressResponse_init_zero {0, 0, 0, 0}
|
||||
#define alox_LedRingProgressRequest_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define alox_LedRingProgressResponse_init_zero {0, 0, 0, 0, 0, 0}
|
||||
#define alox_EspNowFindMeRequest_init_zero {0}
|
||||
#define alox_EspNowFindMeResponse_init_zero {0, 0}
|
||||
#define alox_RestartRequest_init_zero {0}
|
||||
@@ -426,10 +434,15 @@ extern "C" {
|
||||
#define alox_LedRingProgressRequest_intensity_tag 7
|
||||
#define alox_LedRingProgressRequest_blink_ms_tag 8
|
||||
#define alox_LedRingProgressRequest_blink_count_tag 9
|
||||
#define alox_LedRingProgressRequest_client_id_tag 10
|
||||
#define alox_LedRingProgressRequest_all_clients_tag 11
|
||||
#define alox_LedRingProgressRequest_slaves_only_tag 12
|
||||
#define alox_LedRingProgressResponse_success_tag 1
|
||||
#define alox_LedRingProgressResponse_mode_tag 2
|
||||
#define alox_LedRingProgressResponse_progress_tag 3
|
||||
#define alox_LedRingProgressResponse_digit_tag 4
|
||||
#define alox_LedRingProgressResponse_client_id_tag 5
|
||||
#define alox_LedRingProgressResponse_slaves_updated_tag 6
|
||||
#define alox_EspNowFindMeRequest_client_id_tag 1
|
||||
#define alox_EspNowFindMeResponse_success_tag 1
|
||||
#define alox_EspNowFindMeResponse_client_id_tag 2
|
||||
@@ -660,7 +673,10 @@ X(a, STATIC, SINGULAR, UINT32, g, 5) \
|
||||
X(a, STATIC, SINGULAR, UINT32, b, 6) \
|
||||
X(a, STATIC, SINGULAR, UINT32, intensity, 7) \
|
||||
X(a, STATIC, SINGULAR, UINT32, blink_ms, 8) \
|
||||
X(a, STATIC, SINGULAR, UINT32, blink_count, 9)
|
||||
X(a, STATIC, SINGULAR, UINT32, blink_count, 9) \
|
||||
X(a, STATIC, SINGULAR, UINT32, client_id, 10) \
|
||||
X(a, STATIC, SINGULAR, BOOL, all_clients, 11) \
|
||||
X(a, STATIC, SINGULAR, BOOL, slaves_only, 12)
|
||||
#define alox_LedRingProgressRequest_CALLBACK NULL
|
||||
#define alox_LedRingProgressRequest_DEFAULT NULL
|
||||
|
||||
@@ -668,7 +684,9 @@ X(a, STATIC, SINGULAR, UINT32, blink_count, 9)
|
||||
X(a, STATIC, SINGULAR, BOOL, success, 1) \
|
||||
X(a, STATIC, SINGULAR, UINT32, mode, 2) \
|
||||
X(a, STATIC, SINGULAR, UINT32, progress, 3) \
|
||||
X(a, STATIC, SINGULAR, UINT32, digit, 4)
|
||||
X(a, STATIC, SINGULAR, UINT32, digit, 4) \
|
||||
X(a, STATIC, SINGULAR, UINT32, client_id, 5) \
|
||||
X(a, STATIC, SINGULAR, UINT32, slaves_updated, 6)
|
||||
#define alox_LedRingProgressResponse_CALLBACK NULL
|
||||
#define alox_LedRingProgressResponse_DEFAULT NULL
|
||||
|
||||
@@ -826,8 +844,8 @@ extern const pb_msgdesc_t alox_OtaSlaveProgressResponse_msg;
|
||||
#define alox_EspNowFindMeResponse_size 8
|
||||
#define alox_EspNowUnicastTestRequest_size 12
|
||||
#define alox_EspNowUnicastTestResponse_size 8
|
||||
#define alox_LedRingProgressRequest_size 54
|
||||
#define alox_LedRingProgressResponse_size 20
|
||||
#define alox_LedRingProgressRequest_size 64
|
||||
#define alox_LedRingProgressResponse_size 32
|
||||
#define alox_OtaEndPayload_size 0
|
||||
#define alox_OtaPayload_size 209
|
||||
#define alox_OtaSlaveProgressEntry_size 30
|
||||
|
||||
@@ -160,8 +160,8 @@ message EspNowUnicastTestResponse {
|
||||
uint32 seq = 2;
|
||||
}
|
||||
|
||||
// Host → device: LED ring display (progress bar, digit, clear, blink, or find-me).
|
||||
// mode: 0=clear, 1=progress (0–100 %), 2=digit (0–10), 3=blink full ring, 4=find-me (R/G/B ×3 @ full brightness).
|
||||
// Host → master: LED ring on master (client_id=0) and/or slaves via ESP-NOW.
|
||||
// mode: 0=clear, 1=progress (0–100 %), 2=digit (0–10), 3=blink, 4=find-me, 5=all LEDs solid color.
|
||||
message LedRingProgressRequest {
|
||||
uint32 mode = 1;
|
||||
/** 0–100: fraction of ring LEDs to light (mode=progress) */
|
||||
@@ -177,6 +177,12 @@ message LedRingProgressRequest {
|
||||
uint32 blink_ms = 8;
|
||||
/** Number of pulses (mode=blink, default 1) */
|
||||
uint32 blink_count = 9;
|
||||
/** 0 = master ring only; >0 = one slave; ignored when all_clients */
|
||||
uint32 client_id = 10;
|
||||
/** Broadcast to all registered slaves (and optionally master unless slaves_only) */
|
||||
bool all_clients = 11;
|
||||
/** With all_clients: do not change master ring */
|
||||
bool slaves_only = 12;
|
||||
}
|
||||
|
||||
message LedRingProgressResponse {
|
||||
@@ -184,6 +190,8 @@ message LedRingProgressResponse {
|
||||
uint32 mode = 2;
|
||||
uint32 progress = 3;
|
||||
uint32 digit = 4;
|
||||
uint32 client_id = 5;
|
||||
uint32 slaves_updated = 6;
|
||||
}
|
||||
|
||||
/** Host → master: find-me on local ring (client_id=0) or ESP-NOW unicast to one slave. */
|
||||
|
||||
Reference in New Issue
Block a user