Skip to content
This repository was archived by the owner on May 11, 2021. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cli/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>de.spinscale.maxcube</groupId>
<artifactId>maxcube</artifactId>
<version>${version}</version>
<version>0.0.2-SNAPSHOT</version>
</parent>

<artifactId>cli</artifactId>
Expand All @@ -15,7 +15,7 @@
<dependency>
<groupId>de.spinscale.maxcube</groupId>
<artifactId>client</artifactId>
<version>${version}</version>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>io.airlift</groupId>
Expand Down
53 changes: 39 additions & 14 deletions cli/src/main/java/de/spinscale/maxcube/cli/Cli.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,15 @@ public static void main(String[] args) throws IOException {

// argument parsing
io.airlift.airline.Cli.CliBuilder<Runnable> builder = io.airlift.airline.Cli.<Runnable>builder("eq3")
.withCommands(Help.class, Info.class, Discover.class, Version.class, Boost.class, Holiday.class)
.withDescription("Tool to manage Max!EQ3 cubes from the command line")
.withDefaultCommand(Help.class);
.withCommands(Help.class, Info.class, Discover.class, Version.class, Boost.class, Holiday.class,
ManualTemperature.class)
.withDescription("Tool to manage Max!EQ3 cubes from the command line")
.withDefaultCommand(Help.class);

builder.withGroup("report")
.withDescription("Reporting to a configurable backend")
.withCommands(ReportCli.class)
.withDefaultCommand(Help.class);
.withDescription("Reporting to a configurable backend")
.withCommands(ReportCli.class)
.withDefaultCommand(Help.class);

io.airlift.airline.Cli<Runnable> gitParser = builder.build();
gitParser.parse(args).run();
Expand Down Expand Up @@ -138,7 +139,7 @@ public abstract static class CubeHostCommand extends Eq3Command {
@Arguments(description = "host of cube to query")
public String host;

abstract void doRun(String host) throws Exception ;
abstract void doRun(String host) throws Exception;

@Override
void doRun() throws Exception {
Expand All @@ -159,7 +160,7 @@ public static class Discover extends Eq3Command {
@Arguments(description = "interface to scan on, i.e. eth0/en0", required = true)
public String networkInterface;

@Option(name = { "-t", "timeout" } , description = "Time to wait for responses, in seconds, defaults to 2")
@Option(name = {"-t", "timeout"}, description = "Time to wait for responses, in seconds, defaults to 2")
public Integer timeout = 2;

public void doRun() throws Exception {
Expand All @@ -172,7 +173,7 @@ public void doRun() throws Exception {
@Command(name = "boost", description = "Boost a room")
public static class Boost extends CubeHostCommand {

@Option(name = { "-r", "--room" } , description = "The name of the room to boost", required = true)
@Option(name = {"-r", "--room"}, description = "The name of the room to boost", required = true)
public String roomName;

public void doRun(String host) throws Exception {
Expand All @@ -190,13 +191,13 @@ public void doRun(String host) throws Exception {
@Command(name = "holiday", description = "Set holiday mode for a room")
public static class Holiday extends CubeHostCommand {

@Option(name = { "-r", "--room" } , description = "The name of the room to boost", required = true)
@Option(name = {"-r", "--room"}, description = "The name of the room to boost", required = true)
public String roomName;

@Option(name = { "-d", "--duration" } , description = "The duration of boosting", required = true)
@Option(name = {"-d", "--duration"}, description = "The duration of boosting", required = true)
public String duration;

@Option(name = { "-t", "--temperature" } , description = "The temperature in °C", required = true)
@Option(name = {"-t", "--temperature"}, description = "The temperature in °C", required = true)
public Integer temperature;

public void doRun(String host) throws Exception {
Expand All @@ -215,6 +216,28 @@ public void doRun(String host) throws Exception {
}
}

@Command(name = "manualtemp", description = "Set the temperature for a room (manual mode)")
public static class ManualTemperature extends CubeHostCommand {

@Option(name = {"-r", "--room"}, description = "The name of the room to boost", required = true)
public String roomName;

@Option(name = {"-t", "--temperature"}, description = "The temperature in °C in '.5'-steps from 0 to 31.",
required = true)
public Double temperature;

public void doRun(String host) throws Exception {
try (CubeClient client = new SocketCubeClient(host)) {
Cube cube = client.connect();
Room room = cube.findRoom(roomName);
boolean success = client.setManualTemp(room, temperature);
if (!success) {
logger.error("Executing manualtemp call was not successful!");
}
}
}
}

@Command(name = "version", description = "Display version and exit")
public static class Version extends Eq3Command {

Expand All @@ -238,8 +261,10 @@ public void doRun(String host) throws Exception {
}

@Command(name = "info", description = "Return some standard information about the cube. Alias for `report cli`")
public static class Info extends AbstractCliReport {}
public static class Info extends AbstractCliReport {
}

@Command(name = "cli", description = "Return some standard information about the cube to the terminal")
public static class ReportCli extends AbstractCliReport {}
public static class ReportCli extends AbstractCliReport {
}
}
2 changes: 1 addition & 1 deletion client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>de.spinscale.maxcube</groupId>
<artifactId>maxcube</artifactId>
<version>${version}</version>
<version>0.0.2-SNAPSHOT</version>
</parent>

<artifactId>client</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,12 @@ public interface CubeClient extends Closeable {
* @return true if the command was send successfully, false otherwise
*/
boolean holiday(Room room, LocalDateTime endTime, int temperature) throws Exception;

/**
* Sets manually the temperature for a room
* @param room The room to set the temperature
* @param temperature The target temperature in degrees celsius
* @return true if the command was send successfully, false otherwise
*/
boolean setManualTemp(Room room, double temperature) throws Exception;
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ public boolean holiday(Room room, LocalDateTime endTime, int temperature) throws
return this.sendSetTemperatureRequest(data);
}

@Override
public boolean setManualTemp(Room room, double temperature) throws Exception {
String data = Generator.writeSetTemperatureRequest(room, temperature);
return this.sendSetTemperatureRequest(data);
}

private boolean sendSetTemperatureRequest(String base64encodedData) throws Exception {
String dataToSend = base64encodedData + "\r\n";
socket.getOutputStream().write(dataToSend.getBytes(UTF_8));
Expand Down
67 changes: 54 additions & 13 deletions client/src/main/java/de/spinscale/maxcube/data/Generator.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,56 @@ public static void writeRfAddress(int address, ByteArrayOutputStream bos) {
bos.write(address);
}

public static String writeBoostRequest(Room room) throws IOException {
Device thermostat = room.findThermostat();
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
writeSetTemperatureRequest(bos, room.getId(), thermostat.getRfaddress());
// mode & temperature, boost mode is 11 at the beginning, temperature does not matter
bos.write(192);

String base64 = Base64.getEncoder().encodeToString(bos.toByteArray());
return "s:" + base64;
}
}

/**
* https://github.com/Bouni/max-cube-protocol/blob/master/S-Message.md
*/
public static String writeSetTemperatureRequest(Room room, double temperature) throws
IOException {
if (temperature < 0 || temperature > 31) {
throw new IllegalArgumentException("Temperature must be between 0 and 31 °C");
}

double doubledTemp = temperature * 2;
double isIntegerOrDotFive = doubledTemp % 2;

if (isIntegerOrDotFive == 1 || isIntegerOrDotFive == 0) {
Device thermostat = room.findThermostat();
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
writeSetTemperatureRequest(bos, room.getId(), thermostat.getRfaddress());
/*
hex: | 66 |
dual: | 0110 1100 |
|||| ||||
||++-++++-- temperature: 10 1100 -> 38 = temp * 2
|| (to get the temperature, the value must be divided by 2: 38/2 = 19)
++--------- mode:
00=auto/weekly program
01=manual ( => 0100 0000 => Decimal 64)
10=vacation
11=boost */
bos.write(64 + (int) doubledTemp);

String base64 = Base64.getEncoder().encodeToString(bos.toByteArray());
return "s:" + base64;
}
}
else {
throw new IllegalArgumentException("only xx.5 is supported");
}
}

public static String writeHolidayRequest(Room room, LocalDateTime endDate, int temperature) throws IOException {
if (temperature > 31) {
throw new IllegalArgumentException("Temperature must be between 0 and 31 °C");
Expand Down Expand Up @@ -106,22 +156,13 @@ public static void writeDateTimeUntil(LocalDateTime dateTime, ByteArrayOutputStr
bos.write(halfhours);
}

public static String writeBoostRequest(Room room) throws IOException {
Device thermostat = room.findThermostat();
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
writeSetTemperatureRequest(bos, room.getId(), thermostat.getRfaddress());
// mode & temperature, boost mode is 11 at the beginning, temperature does not matter
bos.write(192);

String base64 = Base64.getEncoder().encodeToString(bos.toByteArray());
return "s:" + base64;
}
}

/**
* https://github.com/Bouni/max-cube-protocol/blob/master/S-Message.md
*/
private static void writeSetTemperatureRequest(ByteArrayOutputStream bos, int roomId, int thermostatRfAddress) {
bos.write(0); // unknown
bos.write(4); // rf flags
bos.write(64); // command
bos.write(64); // 0x40 => 64 (decimal) => Set temperature

// rf address from
Generator.writeRfAddress(0, bos);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,9 @@ public void exceptionCaught(IoSession session, Throwable cause) throws Exception
session.closeNow();
}
}

@Override
public boolean setManualTemp(Room room, double temperature) throws Exception {
return false;
}
}
26 changes: 26 additions & 0 deletions client/src/test/java/de/spinscale/maxcube/data/GeneratorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -174,4 +174,30 @@ public void testGeneratorHolidayRequest() throws IOException {
String output = Generator.writeHolidayRequest(room, dateTime, 19);
assertThat(output, is(expectedOutput));
}

@Test
public void testSetTemperatureRequest() throws IOException {
Room room = new Room(1, "foo", 123456);
room.getDevices().add(new Device(DeviceType.THERMOSTAST, "foo", "serial", 1039085));

assertThat("Illegal temperature set", testTemperatureBounds(room, -1));
assertThat("Illegal temperature set", testTemperatureBounds(room, 32));
assertThat("Illegal temperature set", testTemperatureBounds(room, 18.8));
assertThat("Illegal temperature set", testTemperatureBounds(room, 18.3));

String output = Generator.writeSetTemperatureRequest(room, 17.5);
assertThat(output, is("s:AARAAAAAD9rtAWM="));
}

private boolean testTemperatureBounds(Room room, double temp) throws IOException {
boolean exceptionWasThrown = false;
try{
Generator.writeSetTemperatureRequest(room, temp);
}
catch(IllegalArgumentException e){
exceptionWasThrown = true;
}
return exceptionWasThrown;
}

}
8 changes: 4 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
<groupId>de.spinscale.maxcube</groupId>
<artifactId>maxcube</artifactId>
<packaging>pom</packaging>
<version>${version}</version>
<version>0.0.2-SNAPSHOT</version>
<name>maxcube-java</name>

<modules>
<module>cli</module>
<module>client</module>
<module>web</module>
</modules>

<!-- To check for outdated dependencies, run: mvn versions:display-dependency-updates -->
Expand All @@ -19,7 +20,6 @@
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<rr.version>2.5.0</rr.version>
<version>0.0.2-SNAPSHOT</version>
</properties>

<licenses>
Expand Down Expand Up @@ -243,14 +243,14 @@
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<!--build>
<plugins>
<plugin>
<groupId>com.mycila</groupId>
<artifactId>license-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</build-->
</profile>
</profiles>
</project>
8 changes: 8 additions & 0 deletions setup_pi.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash

echo "*** Use 'sudo raspi-config' to setup overclocking, networking, locale and timezone ***"
echo "*** Use 'passwd' to change default password ***"

sudo systemctl enable ssh
sudo systemctl start ssh
sudo apt-get -y install docker git
8 changes: 8 additions & 0 deletions web/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FROM airhacks/wildfly
COPY ./target/maxcube-web.war ${DEPLOYMENT_DIR}
ENV EQ3_HOST=192.168.178.28

# docker exec -i -t micro /bin/bash
# tail -f /opt/wildfly-11.0.0.Final/standalone/log/server.log
# OR
# docker logs micro
36 changes: 36 additions & 0 deletions web/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>de.spinscale.maxcube</groupId>
<artifactId>maxcube</artifactId>
<version>0.0.2-SNAPSHOT</version>
</parent>

<packaging>war</packaging>

<artifactId>web</artifactId>
<name>maxcube web interface</name>

<dependencies>
<dependency>
<groupId>de.spinscale.maxcube</groupId>
<artifactId>cli</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
<build>
<finalName>maxcube-web</finalName>
</build>
</project>
Loading