const { ApolloServer, gql, PubSub } = require("apollo-server"); const Indi = require("@atoy40/indijs"); const IndiDriverInterface = Indi.IndiDriverInterface; // A schema is a collection of type definitions (hence "typeDefs") // that together define the "shape" of queries that are executed against // your data. const typeDefs = gql` enum DriverInterface { GENERAL TELESCOPE CCD GUIDER FOCUSER FILTER DOME GPS WEATHER AO DUSTCAP LIGHTBOX DETECTOR ROTATOR SPECTROGRAPH CORRELATOR AUX } type Property { id: String! name: String vector: Vector device: String permission: Int } interface Vector { id: String! name: String! label: String group: String device: String state: Int permission: Int } type NumberVector implements Vector { id: String! name: String! label: String group: String device: String state: Int permission: Int values: [NumberValue] } type SwitchVector implements Vector { id: String! name: String! label: String group: String device: String state: Int rule: Int permission: Int values: [SwitchValue] } type TextVector implements Vector { id: String! name: String! label: String group: String device: String state: Int permission: Int values: [TextValue] } type LightVector implements Vector { id: String! name: String! label: String group: String device: String state: Int permission: Int values: [LightValue] } type NumberValue { name: String! label: String formated: String value: Float min: Float max: Float step: Float } type SwitchValue { name: String! label: String value: Boolean } type TextValue { name: String! label: String value: String } type LightValue { name: String! label: String value: String } type Device { id: String! name: String properties: [Property] drivers: Int connected: Boolean } input SwitchValueInput { name: String! value: Boolean! } input SwitchInput { device: String! property: String! values: [SwitchValueInput!]! } type Query { connected: Boolean devices: [Device] device(name: String!): Device } type Subscription { connected: Boolean disconnected: Int newDevice: Device newProperty: Property newValue: Vector } type Mutation { connect: Boolean disconnect: Boolean connectDevice(id: String!): Device sendSwitch(input: SwitchInput): Boolean } `; const indi = new Indi.Client("localhost"); const pubsub = new PubSub(); indi .on("connected", () => { pubsub.publish(["CONNECTED"], { connected: true }); }) .on("disconnected", (code) => { pubsub.publish(["CONNECTED"], { connected: false }); pubsub.publish(["DISCONNECTED"], { disconnected: code }); }) .on("newDevice", (device) => { pubsub.publish(["NEW_DEVICE"], { newDevice: device }); }) .on("newProperty", (property) => { console.log("new props "+property.getName()) if ( property.getType() === Indi.PropertyType.Number || property.getType() === Indi.PropertyType.Switch || property.getType() === Indi.PropertyType.Text || property.getType() === Indi.PropertyType.Light ) { pubsub.publish(["NEW_PROPERTY"], { newProperty: property }); } }) .on("newNumber", (n) => { pubsub.publish(["NEW_VALUE"], { newValue: n }); }) .on("newSwitch", (s) => { pubsub.publish(["NEW_VALUE"], { newValue: s }); console.log(s); }) .on("newText", (t) => { pubsub.publish(["NEW_VALUE"], { newValue: t }); }) .on("newLight", (l) => { pubsub.publish(["NEW_VALUE"], { newValue: l }); }) .on("newBlob", (b) => { console.log("new blob"); //pubsub.publish(["NEW_BLOB"], { newValue: l }); }) .on("newMessage", (device, id) => { console.log(device.getDeviceName()); console.log(device.messageQueue(id)); //pubsub.publish(["NEW_VALUE"], { newValue: l }); }); // Resolvers const resolvers = { Query: { connected() { return indi.connected; }, device(_, { name }) { return indi.getDevice(name); }, devices() { return indi.getDevices(); }, }, Mutation: { connect() { return indi.connect(); }, disconnect() { return indi.disconnect(); }, connectDevice(_, { id }) { return indi.connectDevice(id).then(() => indi.getDevice(id)); }, sendSwitch(_, { input: { device, property, values } }) { const dev = indi.getDevice(device); const props = dev.getProperty(property); if (!props) { return false; } const vector = props.getValue(); for (let i = 0; i < vector.values.length; i++) { /*console.log(vector.values[i].name); console.log(vector.values[i].value); console.log(values[i].name); console.log(values[i].value);*/ vector.values[i].value = values[i].value; } return indi .sendNewSwitch(vector) .then(() => true) .catch(() => false); }, }, Subscription: { connected: { subscribe: () => pubsub.asyncIterator(["CONNECTED"]), }, disconnected: { subscribe: () => pubsub.asyncIterator(["DISCONNECTED"]), }, newDevice: { subscribe: () => pubsub.asyncIterator(["NEW_DEVICE"]), }, newProperty: { subscribe: () => pubsub.asyncIterator(["NEW_PROPERTY"]), }, newValue: { subscribe: () => pubsub.asyncIterator(["NEW_VALUE"]), }, }, Device: { id(device) { return device.getDeviceName(); }, name(device) { return device.getDeviceName(); }, properties(device) { return device .getProperties() .filter( (p) => p.getType() === Indi.PropertyType.Number || p.getType() === Indi.PropertyType.Text || p.getType() === Indi.PropertyType.Switch || p.getType() === Indi.PropertyType.Light ); }, drivers(device) { return device.getDriverInterface(); }, }, Property: { id(property) { return property.getDeviceName() + "." + property.getName(); }, name(property) { return property.getName(); }, vector(property) { return property.getValue(); }, device(property) { return property.getDeviceName(); }, permission(property) { return property.getPermission(); } }, Vector: { __resolveType(value) { const dev = indi.getDevice(value.device); const props = dev.getProperty(value.name); switch (props.getType()) { case Indi.PropertyType.Number: return "NumberVector"; case Indi.PropertyType.Switch: return "SwitchVector"; case Indi.PropertyType.Text: return "TextVector"; case Indi.PropertyType.Light: return "LightVector"; default: return null; } }, }, NumberVector: { id(vector) { return vector.device + "." + vector.name; }, }, TextVector: { id(vector) { return vector.device + "." + vector.name; }, }, SwitchVector: { id(vector) { return vector.device + "." + vector.name; }, }, LightVector: { id(vector) { return vector.device + "." + vector.name; }, }, }; const server = new ApolloServer({ typeDefs, resolvers }); //indi.connect().then(() => console.log("INDI connected")); // The `listen` method launches a web server. server.listen().then(({ url, subscriptionsUrl }) => { console.log(`🚀 Server ready at ${url} pubsub=${subscriptionsUrl}`); });