Skip to content

Commit

Permalink
Implement haptics message (#51)
Browse files Browse the repository at this point in the history
Fixes #50
  • Loading branch information
evertonstz authored May 3, 2024
1 parent 7fff83c commit 446f9eb
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 0 deletions.
22 changes: 22 additions & 0 deletions src/components/MainContent/SelectedDevice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
BatteryPercentageMessage,
BrightnessMessage,
ColorThemeMessage,
HapticsMessage,
RequestStatusMessage,
} from '@/pax/core/messages';
import { Messages } from '@/pax/shared/enums';
Expand Down Expand Up @@ -60,6 +61,9 @@ export const SelectedDevice = ({ currentDevice }: SelectedDeviceProps) => {
if (message instanceof BrightnessMessage) {
actions.setBrightness(message.brightness);
}
if (message instanceof HapticsMessage) {
actions.setHaptics(message.percentage);
}
})
.catch(e => {
if (e instanceof BaseBluetoothException) {
Expand Down Expand Up @@ -119,6 +123,23 @@ export const SelectedDevice = ({ currentDevice }: SelectedDeviceProps) => {
void bluetoothState.writeToMainService(toPost.packet);
}}
/>
<Slider
disabled={!bluetoothState.connected && !state.haptics}
max={1}
step={0.1}
value={state.haptics ? [state.haptics] : [0]}
onValueChange={value => {
actions.setHaptics(value[0]);
}}
onValueCommit={value => {
const toPost = post(
HapticsMessage.createWithHaptics(value[0]),
currentDevice,
);
void bluetoothState.writeToMainService(toPost.packet);
}}
/>

<HeaterStatus heaterStatus={state.heatingSate} />
<h1>Device: {!currentDevice ? '' : currentDevice.serial}</h1>
<Button
Expand All @@ -137,6 +158,7 @@ export const SelectedDevice = ({ currentDevice }: SelectedDeviceProps) => {
RequestStatusMessage.createWithMessage([
Messages.ATTRIBUTE_COLOR_THEME,
Messages.ATTRIBUTE_BRIGHTNESS,
Messages.ATTRIBUTE_HAPTIC_MODE,
]),
currentDevice,
);
Expand Down
3 changes: 3 additions & 0 deletions src/pax/containers/api/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
ActualTemperatureMessage,
BatteryPercentageMessage,
BrightnessMessage,
HapticsMessage,
HeaterSetPointMessage,
HeatingStateMessage,
MessageAbs,
Expand Down Expand Up @@ -39,6 +40,8 @@ export const decodeDecryptedPacket = (
return new BatteryPercentageMessage(packet);
case Messages.ATTRIBUTE_BRIGHTNESS:
return BrightnessMessage.createWithPacket(packet);
case Messages.ATTRIBUTE_HAPTIC_MODE:
return HapticsMessage.createWithPacket(packet);
default:
return new UnknownMessage(messageType, packet);
}
Expand Down
109 changes: 109 additions & 0 deletions src/pax/core/messages/HapticsMessage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { PaxDecryptedPacket } from '@/pax/containers/lib';
import { Messages } from '@/pax/shared/enums';

import { MessageAbs } from './MessageAbs';
import { ReadAndWriteMessageAbs } from './ReadAndWriteMessageAbs';

export class HapticsMessage
extends ReadAndWriteMessageAbs
implements MessageAbs
{
readonly percentage: number;
readonly messageType: Messages;
readonly packet: PaxDecryptedPacket;

readonly PaxHapticsAmpMin = 0;
readonly PaxHapticsAmpMax = 128;

constructor(
builder:
| HapticsMessageBuilderFromPacket<HapticsMessage>
| HapticsMessageBuilderFromValue<HapticsMessage>,
) {
super();
this.messageType = Messages.ATTRIBUTE_HAPTIC_MODE;
if (builder instanceof HapticsMessageBuilderFromPacket) {
this.packet = builder.getPacket();
const hapticsAmplitude = this.packet.getUint8(1);
this.percentage = this.hapticsToPercentage(hapticsAmplitude);
} else if (builder instanceof HapticsMessageBuilderFromValue) {
this.percentage = builder.getHaptics();
const buffer = new ArrayBuffer(16);
const view = new PaxDecryptedPacket(buffer);
view.setUint8(0, this.messageType);
view.setUint8(1, this.percentageToHaptics(this.percentage));
this.packet = view;
} else {
throw new Error('Invalid builder');
}
}

private hapticsToPercentage(haptics: number): number {
return (
(haptics - this.PaxHapticsAmpMin) /
(this.PaxHapticsAmpMax - this.PaxHapticsAmpMin)
);
}

private percentageToHaptics(percentage: number): number {
return Math.round(percentage * this.PaxHapticsAmpMax);
}

static createWithPacket(packet: PaxDecryptedPacket): HapticsMessage {
const builder = new HapticsMessageBuilderFromPacket<HapticsMessage>();
builder.setPacket(packet);
return new HapticsMessage(builder);
}

static createWithHaptics(percentage: number): HapticsMessage {
const builder = new HapticsMessageBuilderFromValue<HapticsMessage>();
builder.setBrightness(percentage);
return new HapticsMessage(builder);
}
}

export class HapticsMessageBuilderFromPacket<T extends HapticsMessage> {
private packet?: PaxDecryptedPacket;

setPacket(packet: PaxDecryptedPacket): HapticsMessageBuilderFromPacket<T> {
this.packet = packet;
return this;
}

getPacket(): PaxDecryptedPacket {
if (!this.packet) {
throw new Error('Packet is not set');
}
return this.packet;
}

build(ctor: new (builder: HapticsMessageBuilderFromPacket<T>) => T): T {
if (!this.packet) {
throw new Error('Packet is not set');
}
return new ctor(this);
}
}

export class HapticsMessageBuilderFromValue<T extends HapticsMessage> {
private percentage?: number;

setBrightness(percentage: number): HapticsMessageBuilderFromValue<T> {
this.percentage = percentage;
return this;
}

getHaptics(): number {
if (this.percentage === undefined) {
throw new Error('Percentage is not set');
}
return this.percentage;
}

build(ctor: new (builder: HapticsMessageBuilderFromValue<T>) => T): T {
if (this.percentage === undefined) {
throw new Error('Percentage is not set');
}
return new ctor(this);
}
}
1 change: 1 addition & 0 deletions src/pax/core/messages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export * from './ColorThemeMessage';
export * from './BatteryPercentageMessage';
export * from './BrightnessMessage';
export * from './RequestStatusMessage';
export * from './HapticsMessage';
10 changes: 10 additions & 0 deletions src/state/paxState/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export type PaxActions =
| { type: 'SET_COLOR_THEME'; payload: Pax.lib.ColorTheme }
| { type: 'SET_BATTERY_PERCENTAGE'; payload: number }
| { type: 'SET_BRIGHTNESS'; payload: number }
| { type: 'SET_HAPTICS'; payload: number }
| { type: 'RESET_PAX_STATE' };

export interface BuiltPaxActions {
Expand All @@ -16,6 +17,7 @@ export interface BuiltPaxActions {
setColorTheme: (theme: Pax.lib.ColorTheme) => void;
setBatteryPercentage: (percentage: number) => void;
setBrightness: (brightness: number) => void;
setHaptics: (haptics: number) => void;
resetPaxState: () => void;
}

Expand Down Expand Up @@ -65,6 +67,13 @@ const setBrightness = (
dispatch({ type: 'SET_BRIGHTNESS', payload: brightness });
};

export const setHaptics = (
dispatch: React.Dispatch<PaxActions>,
haptics: number,
) => {
dispatch({ type: 'SET_HAPTICS', payload: haptics });
};

export const buildActions = (
dispatch: React.Dispatch<PaxActions>,
): BuiltPaxActions => {
Expand All @@ -81,5 +90,6 @@ export const buildActions = (
setBatteryPercentage(dispatch, percentage),
resetPaxState: () => resetPaxState(dispatch),
setBrightness: (brightness: number) => setBrightness(dispatch, brightness),
setHaptics: (haptics: number) => setHaptics(dispatch, haptics),
};
};
3 changes: 3 additions & 0 deletions src/state/paxState/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const initialPaxState: PaxState = {
colorTheme: undefined,
batteryPercentage: undefined,
brightness: undefined,
haptics: undefined,
};

const reducer = (state: PaxState, action: PaxActions): PaxState => {
Expand All @@ -24,6 +25,8 @@ const reducer = (state: PaxState, action: PaxActions): PaxState => {
return { ...state, batteryPercentage: action.payload };
case 'SET_BRIGHTNESS':
return { ...state, brightness: action.payload };
case 'SET_HAPTICS':
return { ...state, haptics: action.payload };
case 'RESET_PAX_STATE':
return initialPaxState;
default:
Expand Down
1 change: 1 addition & 0 deletions src/state/paxState/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export interface PaxState {
colorTheme?: Pax.lib.ColorTheme;
batteryPercentage?: number;
brightness?: number;
haptics?: number;
}

0 comments on commit 446f9eb

Please sign in to comment.