Adding the API call for the temperature sensor. (#60)
PBI 30934 * added temperature value * removed deead code * removed dummy * added type to the slider * remove unit notions * changes * changes to the api * created new variable * added degree sign * removed extra spaces * more extra spaces removed * using varaiable for the slider color * added null check * beautifying * beuatifying * solving issues * Update src/view/components/toolbar/InputSlider.tsx Co-Authored-By: Jonathan Wang <jonathanwangg@gmail.com> * used prettier * removed dummy * prettier again * following good unsollicited advices 1 * cleaning up * adding support for stop button * Update src/extension.ts Co-Authored-By: Luke Slevinsky <lslevins@ualberta.ca> * Update src/view/components/toolbar/TemperatureSensorBar.tsx Co-Authored-By: Luke Slevinsky <lslevins@ualberta.ca> * rework setmessage * reformat * let's follow best practices * resolved issue with input
This commit is contained in:
Родитель
59ce0a9a64
Коммит
28d0a68230
|
@ -29,7 +29,8 @@ class Express:
|
|||
(0, 0, 0)
|
||||
],
|
||||
'red_led': False,
|
||||
'switch': False
|
||||
'switch': False,
|
||||
'temperature': 0
|
||||
}
|
||||
|
||||
self.pixels = Pixel(self.__state)
|
||||
|
@ -56,6 +57,10 @@ class Express:
|
|||
def switch(self):
|
||||
return self.__state['switch']
|
||||
|
||||
@property
|
||||
def temperature(self):
|
||||
return self.__state['temperature']
|
||||
|
||||
def __show(self):
|
||||
utils.show(self.__state)
|
||||
|
||||
|
|
|
@ -125,6 +125,7 @@ export enum TelemetryEventName {
|
|||
export enum WebviewMessages {
|
||||
BUTTON_PRESS = "button-press",
|
||||
PLAY_SIMULATOR = "play-simulator",
|
||||
SENSOR_CHANGED = "sensor-changed",
|
||||
REFRESH_SIMULATOR = "refresh-simulator"
|
||||
}
|
||||
|
||||
|
|
|
@ -77,25 +77,33 @@ export function activate(context: vscode.ExtensionContext) {
|
|||
// Handle messages from webview
|
||||
messageListener = currentPanel.webview.onDidReceiveMessage(
|
||||
message => {
|
||||
const messageJson = JSON.stringify(message.text);
|
||||
switch (message.command) {
|
||||
case WebviewMessages.BUTTON_PRESS:
|
||||
// Send input to the Python process
|
||||
handleButtonPressTelemetry(message.text);
|
||||
console.log("About to write");
|
||||
console.log(JSON.stringify(message.text) + "\n");
|
||||
console.log(messageJson + "\n");
|
||||
if (childProcess) {
|
||||
childProcess.stdin.write(JSON.stringify(message.text) + "\n");
|
||||
childProcess.stdin.write(messageJson + "\n");
|
||||
}
|
||||
break;
|
||||
case WebviewMessages.PLAY_SIMULATOR:
|
||||
console.log("Play button");
|
||||
console.log(JSON.stringify(message.text) + "\n");
|
||||
console.log(messageJson + "\n");
|
||||
if (message.text as boolean) {
|
||||
runSimulatorCommand();
|
||||
} else {
|
||||
killProcessIfRunning();
|
||||
}
|
||||
break;
|
||||
case WebviewMessages.SENSOR_CHANGED:
|
||||
console.log("sensor changed");
|
||||
console.log(messageJson + "\n");
|
||||
if (childProcess) {
|
||||
childProcess.stdin.write(messageJson + "\n");
|
||||
}
|
||||
break;
|
||||
case WebviewMessages.REFRESH_SIMULATOR:
|
||||
console.log("Refresh button");
|
||||
runSimulatorCommand();
|
||||
|
@ -150,11 +158,9 @@ export function activate(context: vscode.ExtensionContext) {
|
|||
vscode.window
|
||||
.showInformationMessage(
|
||||
CONSTANTS.INFO.NEW_PROJECT,
|
||||
...[
|
||||
DialogResponses.DONT_SHOW,
|
||||
DialogResponses.EXAMPLE_CODE,
|
||||
DialogResponses.TUTORIALS
|
||||
]
|
||||
)
|
||||
.then((selection: vscode.MessageItem | undefined) => {
|
||||
if (selection === DialogResponses.DONT_SHOW) {
|
||||
|
@ -357,7 +363,7 @@ export function activate(context: vscode.ExtensionContext) {
|
|||
vscode.window
|
||||
.showErrorMessage(
|
||||
CONSTANTS.ERROR.NO_DEVICE,
|
||||
...[DialogResponses.HELP]
|
||||
DialogResponses.HELP
|
||||
)
|
||||
.then((selection: vscode.MessageItem | undefined) => {
|
||||
if (selection === DialogResponses.HELP) {
|
||||
|
@ -382,17 +388,17 @@ export function activate(context: vscode.ExtensionContext) {
|
|||
}
|
||||
});
|
||||
|
||||
// Std error output
|
||||
deviceProcess.stderr.on("data", data => {
|
||||
telemetryAI.trackFeatureUsage(
|
||||
TelemetryEventName.ERROR_PYTHON_DEVICE_PROCESS,
|
||||
{ error: `${data}` }
|
||||
);
|
||||
console.error(
|
||||
`Error from the Python device process through stderr: ${data}`
|
||||
);
|
||||
logToOutputChannel(outChannel, `[ERROR] ${data} \n`, true);
|
||||
});
|
||||
// Std error output
|
||||
deviceProcess.stderr.on("data", data => {
|
||||
telemetryAI.trackFeatureUsage(
|
||||
TelemetryEventName.ERROR_PYTHON_DEVICE_PROCESS,
|
||||
{ error: `${data}` }
|
||||
);
|
||||
console.error(
|
||||
`Error from the Python device process through stderr: ${data}`
|
||||
);
|
||||
logToOutputChannel(outChannel, `[ERROR] ${data} \n`, true);
|
||||
});
|
||||
|
||||
// When the process is done
|
||||
deviceProcess.on("end", (code: number) => {
|
||||
|
@ -431,33 +437,38 @@ export function activate(context: vscode.ExtensionContext) {
|
|||
|
||||
const getActivePythonFile = () => {
|
||||
const editors: vscode.TextEditor[] = vscode.window.visibleTextEditors;
|
||||
const activeEditor = editors.find((editor) => editor.document.languageId === "python");
|
||||
const activeEditor = editors.find(
|
||||
editor => editor.document.languageId === "python"
|
||||
);
|
||||
return activeEditor ? activeEditor.document.fileName : "";
|
||||
}
|
||||
};
|
||||
|
||||
const getFileFromFilePicker = () => {
|
||||
const options: vscode.OpenDialogOptions = {
|
||||
canSelectMany: false,
|
||||
filters: {
|
||||
'All files': ['*'],
|
||||
'Python files': ['py']
|
||||
"All files": ["*"],
|
||||
"Python files": ["py"]
|
||||
},
|
||||
openLabel: 'Run File'
|
||||
openLabel: "Run File"
|
||||
};
|
||||
|
||||
return vscode.window.showOpenDialog(options).then(fileUri => {
|
||||
if (fileUri && fileUri[0]) {
|
||||
console.log('Selected file: ' + fileUri[0].fsPath);
|
||||
console.log(`Selected file: ${fileUri[0].fsPath}`);
|
||||
return fileUri[0].fsPath;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const updateCurrentFileIfPython = async (activeTextEditor: vscode.TextEditor | undefined) => {
|
||||
const updateCurrentFileIfPython = async (
|
||||
activeTextEditor: vscode.TextEditor | undefined
|
||||
) => {
|
||||
if (activeTextEditor && activeTextEditor.document.languageId === "python") {
|
||||
currentFileAbsPath = activeTextEditor.document.fileName;
|
||||
} else if (currentFileAbsPath === "") {
|
||||
currentFileAbsPath = getActivePythonFile() || await getFileFromFilePicker() || "";
|
||||
currentFileAbsPath =
|
||||
getActivePythonFile() || (await getFileFromFilePicker()) || "";
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -496,7 +507,9 @@ const logToOutputChannel = (
|
|||
show: boolean = false
|
||||
) => {
|
||||
if (outChannel) {
|
||||
if (show) { outChannel.show(true); }
|
||||
if (show) {
|
||||
outChannel.show(true);
|
||||
}
|
||||
outChannel.append(message);
|
||||
}
|
||||
};
|
||||
|
@ -522,4 +535,4 @@ function getWebviewContent(context: vscode.ExtensionContext) {
|
|||
}
|
||||
|
||||
// this method is called when your extension is deactivated
|
||||
export function deactivate() { }
|
||||
export function deactivate() {}
|
||||
|
|
|
@ -30,6 +30,8 @@ class UserInput(threading.Thread):
|
|||
'button_b', cpx._Express__state['button_b'])
|
||||
cpx._Express__state['switch'] = new_state.get(
|
||||
'switch', cpx._Express__state['switch'])
|
||||
cpx._Express__state['temperature'] = new_state.get(
|
||||
'temperature', cpx._Express__state['temperature'])
|
||||
except Exception as e:
|
||||
print("Error trying to send event to the process : ",
|
||||
e, file=sys.stderr, flush=True)
|
||||
|
|
|
@ -55,7 +55,6 @@ interface vscode {
|
|||
declare const vscode: vscode;
|
||||
|
||||
const sendMessage = (type: string, state: any) => {
|
||||
console.log("sendmessage");
|
||||
vscode.postMessage({ command: type, text: state });
|
||||
};
|
||||
|
||||
|
|
|
@ -2,88 +2,131 @@
|
|||
// Licensed under the MIT license.
|
||||
|
||||
import * as React from "react";
|
||||
import "./InputSlider.css"
|
||||
import "./InputSlider.css";
|
||||
|
||||
interface ISliderProps{
|
||||
min:number;
|
||||
max: number;
|
||||
min_label: string;
|
||||
max_label: string;
|
||||
step:number;
|
||||
type: string;
|
||||
interface vscode {
|
||||
postMessage(message: any): void;
|
||||
}
|
||||
|
||||
declare const vscode: vscode;
|
||||
|
||||
const sendMessage = (state: any) => {
|
||||
vscode.postMessage({ command: "sensor-changed", text: state });
|
||||
};
|
||||
|
||||
class InputSlider extends React.Component<ISliderProps,any,any>{
|
||||
interface ISliderProps {
|
||||
min: number;
|
||||
max: number;
|
||||
min_label: string;
|
||||
max_label: string;
|
||||
step: number;
|
||||
type: string;
|
||||
}
|
||||
|
||||
constructor(props: ISliderProps){
|
||||
super(props);
|
||||
this.state = {
|
||||
value: 0
|
||||
};
|
||||
class InputSlider extends React.Component<ISliderProps, any, any> {
|
||||
constructor(props: ISliderProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
value: 0
|
||||
};
|
||||
|
||||
this.handleOnChange = this.handleOnChange.bind(this);
|
||||
this.validateRange = this.validateRange.bind(this);
|
||||
this.handleOnChange = this.handleOnChange.bind(this);
|
||||
this.validateRange = this.validateRange.bind(this);
|
||||
}
|
||||
|
||||
handleMessage = (event: any): void => {
|
||||
const message = event.data; // The JSON data our extension sent
|
||||
switch (message.command) {
|
||||
case "reset-state":
|
||||
this.setState({ value: 0 });
|
||||
break;
|
||||
case "set-state":
|
||||
console.log("Setting the state: " + JSON.stringify(message.state));
|
||||
break;
|
||||
default:
|
||||
console.log("Invalid message received from the extension.");
|
||||
this.setState({ value: 0 });
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div className="inputSlider">
|
||||
<input type="text" className="sliderValue" value={this.state.value}
|
||||
onInput={this.handleOnChange} defaultValue={this.props.min.toLocaleString()} pattern="^-?[0-9]*$" onKeyUp={this.validateRange}/>
|
||||
<div className="sliderArea">
|
||||
<div className="upLabelArea">
|
||||
<div className='minLabel'>
|
||||
{this.props.min_label}
|
||||
</div>
|
||||
<div className='maxLabel'>
|
||||
{this.props.max_label}
|
||||
</div>
|
||||
</div>
|
||||
<input type="range" className="slider" min={this.props.min} max={this.props.max}
|
||||
step={this.props.step} onChange={this.handleOnChange} value={this.state.value} defaultValue={this.props.min.toLocaleString()}/>
|
||||
<div className="downLabelArea">
|
||||
<div className='minLabel'>
|
||||
{this.props.min}
|
||||
</div>
|
||||
<div className='maxLabel'>
|
||||
{this.props.max}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
componentDidMount() {
|
||||
console.log("Mounted");
|
||||
window.addEventListener("message", this.handleMessage);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
// Make sure to remove the DOM listener when the component is unmounted.
|
||||
window.removeEventListener("message", this.handleMessage);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div className="inputSlider">
|
||||
<input
|
||||
type="text"
|
||||
className="sliderValue"
|
||||
value={this.state.value}
|
||||
onInput={this.handleOnChange}
|
||||
defaultValue={this.props.min.toLocaleString()}
|
||||
pattern="^-?[0-9]*$"
|
||||
onKeyUp={this.validateRange}
|
||||
/>
|
||||
<div className="sliderArea">
|
||||
<div className="upLabelArea">
|
||||
<div className="minLabel">{this.props.min_label}</div>
|
||||
<div className="maxLabel">{this.props.max_label}</div>
|
||||
</div>
|
||||
<input
|
||||
type="range"
|
||||
className="slider"
|
||||
min={this.props.min}
|
||||
max={this.props.max}
|
||||
step={this.props.step}
|
||||
onChange={this.handleOnChange}
|
||||
value={this.state.value}
|
||||
defaultValue={this.props.min.toLocaleString()}
|
||||
/>
|
||||
<div className="downLabelArea">
|
||||
<div className="minLabel">{this.props.min}</div>
|
||||
<div className="maxLabel">{this.props.max}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
)
|
||||
private handleOnChange(event: React.ChangeEvent<HTMLInputElement>) {
|
||||
this.updateValue(event);
|
||||
this.validateRange();
|
||||
const newSensorState = this.writeMessage(event);
|
||||
if (newSensorState) {
|
||||
sendMessage(newSensorState);
|
||||
}
|
||||
}
|
||||
|
||||
private handleOnChange(event: React.ChangeEvent<HTMLInputElement>){
|
||||
this.updateValue(event);
|
||||
this.validateRange();
|
||||
|
||||
|
||||
private writeMessage(event: React.ChangeEvent<HTMLInputElement>) {
|
||||
parseInt(event.target.value, 10);
|
||||
return this.props.type && this.state.value && event.target.value
|
||||
? { temperature: parseInt(event.target.value, 10) }
|
||||
: undefined;
|
||||
}
|
||||
|
||||
private updateValue(event: React.ChangeEvent<HTMLInputElement>) {
|
||||
const newValue = event.target.validity.valid
|
||||
? event.target.value
|
||||
: this.state.value;
|
||||
console.log(`set state to ${this.state.value}`);
|
||||
this.setState({ value: newValue });
|
||||
}
|
||||
|
||||
private validateRange() {
|
||||
if (this.state.value < this.props.min) {
|
||||
this.setState({ value: this.props.min });
|
||||
}
|
||||
|
||||
private updateValue(event: React.ChangeEvent<HTMLInputElement>){
|
||||
const newValue = (event.target.validity.valid) ? event.target.value : this.state.value;
|
||||
this.setState({value:newValue});
|
||||
|
||||
if (this.state.value > this.props.max) {
|
||||
this.setState({ value: this.props.max });
|
||||
}
|
||||
|
||||
private validateRange(){
|
||||
if(this.state.value<this.props.min){
|
||||
this.setState({value:this.props.min,dummy:2});
|
||||
}
|
||||
if(this.state.value>this.props.max){
|
||||
this.setState({value:this.props.max,dummy:1});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export default InputSlider;
|
||||
|
||||
|
|
|
@ -3,55 +3,52 @@
|
|||
|
||||
import * as React from "react";
|
||||
import InputSlider from "./InputSlider";
|
||||
import "./TemperatureSensorBar.css"
|
||||
import "./TemperatureSensorBar.css";
|
||||
|
||||
const TEMPERATURE_SENSOR_PROPERTIES = {
|
||||
MIN_LABEL: "Cold",
|
||||
MAX_LABEL: "Hot",
|
||||
LABEL: "Temperature sensor",
|
||||
TYPE: "temperature",
|
||||
}
|
||||
|
||||
LABEL: "Temperature sensor",
|
||||
MAX_LABEL: "Hot",
|
||||
MIN_LABEL: "Cold",
|
||||
TYPE: "temperature"
|
||||
};
|
||||
|
||||
interface ITemperatureUnit {
|
||||
name: string,
|
||||
minValue: number,
|
||||
maxValue: number
|
||||
unitLabel: string;
|
||||
minValue: number;
|
||||
maxValue: number;
|
||||
}
|
||||
|
||||
const CELSIUS_STATE: ITemperatureUnit ={
|
||||
name: "°C",
|
||||
minValue: -40,
|
||||
maxValue: 40
|
||||
}
|
||||
const CELSIUS_STATE: ITemperatureUnit = {
|
||||
maxValue: 40,
|
||||
minValue: -40,
|
||||
unitLabel: "°C"
|
||||
};
|
||||
|
||||
class TemperatureSensorBar extends React.Component<any, ITemperatureUnit, any> {
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.state = CELSIUS_STATE;
|
||||
}
|
||||
|
||||
class TemperatureSensorBar extends React.Component<any,ITemperatureUnit,any>{
|
||||
|
||||
constructor(props: any){
|
||||
super(props);
|
||||
this.state = CELSIUS_STATE
|
||||
}
|
||||
|
||||
render(){
|
||||
|
||||
|
||||
return (
|
||||
<div className="temperatureSensorBar">
|
||||
<div className="header">
|
||||
<div className="title">{TEMPERATURE_SENSOR_PROPERTIES.LABEL+" "+CELSIUS_STATE.name}</div>
|
||||
|
||||
</div>
|
||||
<InputSlider min={this.state.minValue} max={this.state.maxValue} type={TEMPERATURE_SENSOR_PROPERTIES.TYPE}
|
||||
min_label={TEMPERATURE_SENSOR_PROPERTIES.MIN_LABEL} max_label={TEMPERATURE_SENSOR_PROPERTIES.MAX_LABEL}
|
||||
step={1} />
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="temperatureSensorBar">
|
||||
<div className="header">
|
||||
<div className="title">
|
||||
{`${TEMPERATURE_SENSOR_PROPERTIES.LABEL} ${CELSIUS_STATE.unitLabel}`}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
<InputSlider
|
||||
min={this.state.minValue}
|
||||
max={this.state.maxValue}
|
||||
type={TEMPERATURE_SENSOR_PROPERTIES.TYPE}
|
||||
min_label={TEMPERATURE_SENSOR_PROPERTIES.MIN_LABEL}
|
||||
max_label={TEMPERATURE_SENSOR_PROPERTIES.MAX_LABEL}
|
||||
step={1}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default TemperatureSensorBar;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче