Skip to content

Commit

Permalink
Merge pull request #543 from Sienci-Labs/MI-features-machine-status
Browse files Browse the repository at this point in the history
Features: Machine Status
  • Loading branch information
sophiabeluli committed Sep 3, 2024
2 parents 129af06 + ea335f6 commit f3b10e2
Show file tree
Hide file tree
Showing 6 changed files with 289 additions and 10 deletions.
20 changes: 11 additions & 9 deletions src/app/src/components/shadcn/Tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,17 @@ const TooltipContent = React.forwardRef<
React.ElementRef<typeof TooltipPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cx(
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
<TooltipPrimitive.Portal>
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cx(
"bg-gray-500 text-white z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
</TooltipPrimitive.Portal>
))
TooltipContent.displayName = TooltipPrimitive.Content.displayName

Expand Down
61 changes: 61 additions & 0 deletions src/app/src/features/MachineStatus/AlarmDescriptionIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright (C) 2021 Sienci Labs Inc.
*
* This file is part of gSender.
*
* gSender is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, under version 3 of the License.
*
* gSender is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with gSender. If not, see <https://www.gnu.org/licenses/>.
*
* Contact for information regarding this program and its license
* can be sent through gSender@sienci.com or mailed to the main office
* of Sienci Labs Inc. in Waterloo, Ontario, Canada.
*
*/

import get from 'lodash/get';
import cx from 'classnames';
import { store as reduxStore } from '../../store/redux';
import { GRBLHAL } from '../../constants';
import { GRBL_HAL_ALARMS } from '../../../../server/controllers/Grblhal/constants';
import { GRBL_ALARMS } from '../../../../server/controllers/Grbl/constants';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from 'components/shadcn/Tooltip';
import { ALARM_CODE } from './definitions';

const getCodeDescription = (code: number | 'Homing' = 1): string => {
const controllerType: string = get(reduxStore.getState(), 'controller.type');
const ALARMS = controllerType === GRBLHAL ? GRBL_HAL_ALARMS : GRBL_ALARMS;
const alarm = ALARMS.find(alarm => alarm.code === code);
if (alarm) {
return alarm.description;
}
return 'Invalid alarm code - no matching description found';
};

const AlarmDescriptionIcon = ({ code = 1 }: { code: ALARM_CODE }) => {
const alarmDescription = getCodeDescription(code);
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<div className="bg-white opacity-90 rounded-full w-8 h-8 my-0 mx-4 flex items-center justify-center shadow-[rgba(0,0,0,0.35)_0px_5px_15px] [pointer-events:_all]">
<i className={cx("fas fa-question", "text-xl text-gray-600")} />
</div>
</TooltipTrigger>
<TooltipContent className="max-w-64">
{alarmDescription}
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
};

export default AlarmDescriptionIcon;
139 changes: 139 additions & 0 deletions src/app/src/features/MachineStatus/MachineStatus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Copyright (C) 2021 Sienci Labs Inc.
*
* This file is part of gSender.
*
* gSender is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, under version 3 of the License.
*
* gSender is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with gSender. If not, see <https://www.gnu.org/licenses/>.
*
* Contact for information regarding this program and its license
* can be sent through gSender@sienci.com or mailed to the main office
* of Sienci Labs Inc. in Waterloo, Ontario, Canada.
*
*/

import { connect } from 'react-redux';
import cx from 'classnames';
import get from 'lodash/get';
import controller from '../../lib/controller';
import AlarmDescriptionIcon from './AlarmDescriptionIcon';
import UnlockButton from './UnlockButton';
import { GRBL_ACTIVE_STATE_ALARM, GRBL_ACTIVE_STATE_CHECK, GRBL_ACTIVE_STATE_HOLD, GRBL_ACTIVE_STATE_HOME, GRBL_ACTIVE_STATE_IDLE, GRBL_ACTIVE_STATE_JOG, GRBL_ACTIVE_STATE_RUN } from '../../constants';
import { GRBL_ACTIVE_STATES_T } from 'definitions/general';
import { ALARM_CODE } from './definitions';

interface MachineStatusProps {
alarmCode: ALARM_CODE,
activeState: GRBL_ACTIVE_STATES_T,
isConnected: boolean,
};

interface Message {
[key: GRBL_ACTIVE_STATES_T]: string
}

/**
* Control Area component displaying machine status
* @param {Object} state Default state given from parent component
* @param {Object} actions Actions object given from parent component
*/
const MachineStatus: React.FC<MachineStatusProps> = ({ activeState, alarmCode, isConnected }) => {
const unlock = (): void => {
if (
alarmCode === 1 ||
alarmCode === 2 ||
alarmCode === 10 ||
alarmCode === 14 ||
alarmCode === 17
) {
controller.command('reset:limit');
return;
} else if (alarmCode === 'Homing' || alarmCode === 11) {
controller.command('homing');
return;
}
controller.command('unlock');
}

/**
* Function to output the machine state based on multiple conditions
*/
const machineStateRender = (): React.ReactElement => {
const message: Message = {
Idle: 'Idle',
Run: 'Running',
Hold: 'Hold',
Jog: 'Jogging',
Check: 'Check',
Home: 'Homing',
Sleep: 'Sleep',
Alarm: 'Alarm',
Disconnected: 'Disconnected',
};

return (
<div className="flex relative flex-col items-center">
<div className={cx(
"flex w-72 h-[70px] justify-between items-center bg-black [clip-path:_polygon(0%_0%,_100%_0%,_85%_100%,_15%_100%)]", //[border-top:50px_solid_black] [border-left:25px_solid_transparent] [border-right:25px_solid_transparent]",
{
"text-white": !isConnected || !activeState,
"bg-gray-500 text-white": activeState === GRBL_ACTIVE_STATE_IDLE,
"bg-green-600 text-white": activeState === GRBL_ACTIVE_STATE_RUN || activeState === GRBL_ACTIVE_STATE_JOG || activeState === GRBL_ACTIVE_STATE_CHECK,
"bg-blue-500 text-white": activeState === GRBL_ACTIVE_STATE_HOME,
"bg-yellow-600 text-white": activeState === GRBL_ACTIVE_STATE_HOLD,
"bg-red-500 text-white": activeState === GRBL_ACTIVE_STATE_ALARM
}
)}>
{
isConnected && activeState ? (
<>
{
activeState === GRBL_ACTIVE_STATE_ALARM ? (
<div className="flex w-full flex-row justify-center align-middle items-center font-light text-3xl mb-1">
<div className="flex justify-center">{activeState}</div>
<div className="absolute right-3 flex float-right"><AlarmDescriptionIcon code={alarmCode} /></div>
</div>
) : (
<span className="flex w-full font-light text-3xl mb-1 justify-center">{message[activeState]}</span>
)
}
</>
) : <h1 className="flex w-full font-light text-3xl mb-1 justify-center">Disconnected</h1>
}
</div>
<div className="mt-4">
{ (activeState === GRBL_ACTIVE_STATE_ALARM || activeState === GRBL_ACTIVE_STATE_HOLD) && <UnlockButton onClick={unlock} alarmCode={alarmCode} activeState={activeState} /> }
</div>
</div>
)
};

return (
// calc = half of width + sidebar width
<div className="absolute top-0 left-1/2 -ml-[calc(128px-50px)] w-64 z-10 overflow-visible"> {/*className="grid grid-cols-[2fr_2fr_2fr]">*/}
{machineStateRender()}
</div>
);
}

export default connect((store) => {
const $22 = get(store, 'controller.settings.settings.$22', '0');
const alarmCode = get(store, 'controller.state.status.alarmCode');
const activeState = get(store, 'controller.state.status.activeState');
const isConnected = get(store, 'connection.isConnected');
return {
$22,
alarmCode,
activeState,
isConnected
};
})(MachineStatus);
74 changes: 74 additions & 0 deletions src/app/src/features/MachineStatus/UnlockButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright (C) 2021 Sienci Labs Inc.
*
* This file is part of gSender.
*
* gSender is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, under version 3 of the License.
*
* gSender is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with gSender. If not, see <https://www.gnu.org/licenses/>.
*
* Contact for information regarding this program and its license
* can be sent through gSender@sienci.com or mailed to the main office
* of Sienci Labs Inc. in Waterloo, Ontario, Canada.
*
*/

import React, { MouseEventHandler } from 'react';
import cx from 'classnames';

import { GRBL_ACTIVE_STATE_ALARM } from '../../constants';
import { GRBL_ACTIVE_STATES_T } from 'definitions/general';
import { ALARM_CODE } from './definitions';

export interface UnlockProps {
activeState: GRBL_ACTIVE_STATES_T,
alarmCode: ALARM_CODE,
onClick: MouseEventHandler<HTMLButtonElement>,
};

const UnlockButton: React.FC<UnlockProps> = ({ activeState, alarmCode, onClick }) => {
const getButtonText = (): string => {
if (alarmCode === 11) {
return 'Click to Run Homing';
}
return 'Click to Unlock Machine';
};

return (
<div className="flex items-center justify-center pointer-events-auto">
<button
type="button"
className={cx(
"w-[8.5rem] flex flex-row items-center justify-between p-3 rounded-3xl leading-tight line-s text-white border-solid border-[1px] opacity-90 hover:opacity-70",
{
"border-red-800 bg-red-600 grow [animation:grow_2s_infinite]": activeState === GRBL_ACTIVE_STATE_ALARM,
"border-yellow-800 bg-yellow-600": activeState !== GRBL_ACTIVE_STATE_ALARM,
"pr-1": alarmCode !== 'Homing' && alarmCode !== 11 // this is for adjusting the position of the text
}
)}
onClick={onClick}
>
<i
className={cx(
"text-5xl",
"fas",
activeState === GRBL_ACTIVE_STATE_ALARM && (alarmCode === 'Homing' || alarmCode === 11) ? 'fa-home' : 'fa-unlock'
)}
role="button"
tabIndex={-1}
/>
{getButtonText()}
</button>
</div>
);
};

export default UnlockButton;
1 change: 1 addition & 0 deletions src/app/src/features/MachineStatus/definitions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type ALARM_CODE = number | 'Homing';
4 changes: 3 additions & 1 deletion src/app/src/workspace/TopBar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import MachineStatus from 'features/MachineStatus/MachineStatus';
import gSenderIcon from './assets/icon-round.png';
import Connection from "features/Connection";

export const TopBar = () => {
return <div className="border p-3 h-20 box-borde flex gap-4 items-center bg-gray-50">
return <div className="border p-3 h-16 box-borde flex gap-4 items-center bg-gray-50">
<div className="w-[50px] h-[50px]">
<img alt="gSender Logo" src={gSenderIcon}/>
</div>
<Connection />
<MachineStatus />
</div>;
};

0 comments on commit f3b10e2

Please sign in to comment.