tello-custom-ip
Version:
Tello drone client with custom IP address support, forked from @0x77/tellots
103 lines (91 loc) • 3.15 kB
text/typescript
import constants from "./constants";
import { getTelloIP } from "./config";
import dgram from "dgram";
import { ResponseParser, CommandType } from "./types";
import { parseCommandResponse } from "./parsers";
const client = dgram.createSocket('udp4'),
_local = {
state: "idle"
}
client.on('message', (msg) => {
_local.state = msg.toString()
});
client.bind(constants.ports.response)
const bindStateManagement = (resolve: Function, reject: Function, parser?: ResponseParser) => {
let timeoutId = setTimeout(() => {
_local.state = "error"
}, 10000);
let intervalId = setInterval(() => {
if (isIdle())
return
if (isError())
reject(_local.state)
else {
const rawResponse = _local.state;
if (parser) {
// Parse the response using the provided parser
try {
const parsedResponse = parser(rawResponse);
resolve(parsedResponse);
} catch (error) {
reject(error);
}
} else {
// Return raw response if no parser is provided
resolve(rawResponse);
}
}
clearInterval(intervalId)
clearTimeout(timeoutId)
_local.state = "idle"
}, 100);
}
const isIdle = () => _local.state === "idle"
const isError = () => _local.state === "error"
const transmit = (command: string) => {
const message = Buffer.from(command)
client.send(message, 0, message.length, constants.ports.command, getTelloIP(), (error) => {
if (error)
_local.state = "error"
})
}
/**
* Send a command to the Tello drone
* @param command - The command to send
* @param parser - Optional parser function to convert the response to a specific type
* @param type - The type of command (used for determining default parser)
* @returns Promise resolving to the parsed response
*/
const send = <T = string>(
command: string,
parser?: ResponseParser<T>,
type: CommandType = CommandType.READ
): Promise<T> => {
return new Promise((resolve, reject) => {
if (!isIdle())
reject("error")
// Use provided parser or default based on command type
const responseParser = parser || getDefaultParser<T>(type);
bindStateManagement(resolve, reject, responseParser)
transmit(command)
})
}
/**
* Get the default parser based on command type
*/
const getDefaultParser = <T>(type: CommandType): ResponseParser<T> => {
switch (type) {
case CommandType.CONTROL:
case CommandType.SET:
// For control and set commands, parse "ok" as true, anything else as false
return ((response: string) => {
return parseCommandResponse(response) as unknown as T;
});
case CommandType.READ:
default:
// For read commands, return the raw string
return ((response: string) => response as unknown as T);
}
}
export const exchanger = { send, _local };
export default exchanger;