You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

441 lines
9.3 KiB

const { ApolloServer, gql, PubSub } = require("apollo-server");
const Indi = require("@atoy40/indijs");
const fs = require("fs");
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: Int
}
type Device {
id: String!
name: String
properties: [Property]
drivers: Int
connected: Boolean
}
type Message {
id: String
device: Device!
message: String!
}
input NumberValueInput {
name: String!
value: Float!
}
input NumberInput {
device: String!
property: String!
values: [NumberValueInput!]!
}
input OneNumberInput {
device: String!
property: String!
name: String!
value: Float!
}
input SwitchValueInput {
name: String!
value: Boolean!
}
input SwitchInput {
device: String!
property: String!
values: [SwitchValueInput!]!
}
input OneTextInput {
device: String!
property: String!
name: String!
value: String!
}
type Query {
connected: Boolean
devices: [Device]
device(name: String!): Device
}
type Subscription {
connected: Boolean
disconnected: Int
newDevice: Device
newProperty: Property
newValue: Vector
newMessage: Message
}
type Mutation {
connect: Boolean
disconnect: Boolean
connectDevice(id: String!): Device
sendOneNumber(input: OneNumberInput!): Boolean
sendNumber(input: NumberInput!): Boolean
sendSwitch(input: SwitchInput!): Boolean
sendOneText(input: OneTextInput!): 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) => {
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 });
})
.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 " + b.length);
fs.writeFile("test.fits", b, (err) => {
if (err) {
console.log("unable to save buffer");
return;
}
console.log("test.fits saved");
});
//pubsub.publish(["NEW_BLOB"], { newValue: l });
})
.on("newMessage", (device, id) => {
console.log(device.messageQueue(id));
pubsub.publish(["NEW_MESSAGE"], {
newMessage: {
id: device.getDeviceName() + "." + id,
device,
message: device.messageQueue(id),
},
});
});
// 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));
},
sendNumber(_, { 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++) {
vector.values[i].value = values[i].value;
}
return indi
.sendNewNumber(vector)
.then(() => true)
.catch(() => false);
},
sendOneNumber(_, { input: { device, property, name, value } }) {
return indi
.sendNewNumber(device, property, name, value)
.then(() => true)
.catch(() => false);
},
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++) {
vector.values[i].value = values[i].value;
}
return indi
.sendNewSwitch(vector)
.then(() => true)
.catch(() => false);
},
sendOneText(_, { input: { device, property, name, value } }) {
return indi
.sendNewText(device, property, name, value)
.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"]),
},
newMessage: {
subscribe: () => pubsub.asyncIterator(["NEW_MESSAGE"]),
},
},
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}`);
});