/** * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.md file. */ package org.mule.module.hue; import org.mule.api.ConnectionException; import org.mule.api.ConnectionExceptionCode; import org.mule.api.annotations.Category; import org.mule.api.annotations.Configurable; import org.mule.api.annotations.Connector; import org.mule.api.annotations.Processor; import org.mule.api.annotations.display.FriendlyName; import org.mule.api.annotations.display.Placement; import org.mule.api.annotations.lifecycle.Start; import org.mule.api.annotations.param.ConnectionKey; import org.mule.api.annotations.param.Optional; import org.mule.module.hue.model.Command; import org.mule.module.hue.model.GroupAttributes; import org.mule.module.hue.model.LightAttributes; import org.mule.module.hue.model.Schedule; import org.mule.module.hue.model.State; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.WebResource; import java.io.IOException; import org.codehaus.jackson.map.ObjectMapper; /** * Connects to the Philips Hue smart lighting system. * This connector does not cover the full API rather the more common things that * a developer would automate from Mule. * * {@sample.xml ../../../doc/hue-connector.xml.sample hue:config} * * @author ross@mulesoft.com */ @Connector(name = "hue", schemaVersion = "1.0", friendlyName = "Philips Hue", minMuleVersion = "3.4.0") @Category(name = "org.mule.tooling.ui.modules.core.miscellaneous", description = "Miscellaneous") public class HueConnector { /** * The expected date format by this service - used to create scheduled commands */ public static final String ISO86012004Format = "yyyy-MM-ddThh:mm:ss"; /** * The local ip address for the hue base station */ @Configurable private String ipAddress; /** * the username that has access to the hue base station */ @Configurable @ConnectionKey private String username; private Client httpClient = Client.create(); private ObjectMapper mapper = new ObjectMapper(); /** * The local ip address for the hue base station * * @return The local ip address for the hue base station */ public String getIpAddress() { return ipAddress; } /** * Sets the local ip address for the hue base station * * @param ipAddress the local ip address for the hue base station */ public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; } /** * Gets the username that has access to the hue base station * * @return the username that has access to the hue base station */ public String getUsername() { return username; } /** * Sets the username that has access to the hue base station * * @param userName the username that has access to the hue base station */ public void setUsername(String username) { this.username = username; } /** * Connect * * @throws ConnectionException */ @Start public void connect() throws ConnectionException { String res = httpClient.resource(getBaseUri()).get(String.class); if (res.contains("error")) { throw new ConnectionException(ConnectionExceptionCode.INCORRECT_CREDENTIALS, "unauthorized user", res); } } /** * Sets the state of an individual light * <p/> * {@sample.xml ../../../doc/Hue-connector.xml.sample hue:set-light-state} * * @param lightId the identifier for the light to change * @param state the new state to apply to the light * @return The new state of the light * @throws IOException if there is a connection error or if the call returns an error response */ @Processor public State setLightState(String lightId, State state) throws IOException { WebResource resource = httpClient.resource(getBaseUri() + "/lights/" + lightId + "/state"); String st = mapper.writeValueAsString(state); String response = resource.put(String.class, st); if (response.contains("error")) { throw new IOException(response); } return state; } /** * Sets the state of a light group. All lights in the group will be given the same state * <p/> * {@sample.xml ../../../doc/Hue-connector.xml.sample hue:set-group-state} * * @param groupId the identifier for the group to change. The bridge has a default group is 0 which includes all lights known by the bridge * @param state the new state to apply to the group * @return The new state of the group * @throws IOException if there is a connection error or if the call returns an error response */ @Processor public State setGroupState(String groupId, @Placement(group = "State") State state) throws IOException { WebResource resource = httpClient.resource(getBaseUri() + "/groups/" + groupId + "/action"); String response = resource.put(String.class, mapper.writeValueAsString(state)); if (response.contains("error")) { throw new IOException(response); } return state; } /** * Gets a list of all lights that have been discovered by the bridge * <p/> * {@sample.xml ../../../doc/Hue-connector.xml.sample hue:get-lights} * * @return a list of all lights in the system, each light has a name and unique identification number. * If there are no lights in the system then the bridge will return an empty object, {}. * @throws IOException if there is a connection error or if the call returns an error response */ @Processor public String getLights() throws IOException { WebResource resource = httpClient.resource(getBaseUri() + "/lights"); String response = resource.get(String.class); if (response.contains("error")) { throw new IOException(response); } return response; } /** * Creates a scheduled command tht will execute at a specific date and time * <p/> * {@sample.xml ../../../doc/Hue-connector.xml.sample hue:create-schedule} * * @param command Representation of a command that that can be sent to the scheduling * API to execute the command at a specific time * i.e. 'turn the lights on in the morning at 7am' * A command represents a resource address, the HTTP verb and the body as the data to * send to the resource. * @param scheduleName for the new schedule. If a name is not specified then the default name, “schedule”, is used. * If the name is already taken a space and number will be appended by the bridge, e.g. “schedule 1”. * @param time Time when the scheduled event will occur in ISO 8601:2004 format. * The bridge measures time in UTC and only accepts extended format, non-recurring, local time (YYYY-MM-DDThh:mm:ss). * Incorrectly formatted dates will raise an error of type 7. If the time is in the past an error 7 will also be raised. * @param description Description of the new schedule. If the description is not specified it will be empty. * * @return a string json response with either success message. If there is an error returned then an IOExecption is thrown * @throws IOException if there is a connection error or if the call returns an error response */ @Processor public String createSchedule(@Placement(group = "Schedule", order = 1) @FriendlyName("Name") String scheduleName, @Placement(group = "Schedule", order = 2) String time, @Placement(group = "Schedule", order = 3) @Optional String description, @Placement(group = "Command to Execute") Command command) throws IOException { Schedule s = new Schedule(); s.setCommand(command); s.setName(scheduleName); s.setTime(time); s.setDescription(description); WebResource resource = httpClient.resource(getBaseUri() + "/schedules"); String response = resource.post(String.class, mapper.writeValueAsString(s)); if (response.contains("error")) { throw new IOException(response); } return response; } /** * Gets the current state of an individual light * <p/> * {@sample.xml ../../../doc/Hue-connector.xml.sample hue:get-light-state} * * @param lightId the identifier of the light to query state * * @return The complete state of the light * @throws IOException if there is a connection error or if the call returns an error response */ @Processor public LightAttributes getLightState(String lightId) throws IOException { WebResource resource = httpClient.resource(getBaseUri() + "/lights/" + lightId); String response = resource.get(String.class); if (response.contains("error")) { throw new IOException(response); } System.out.println("This:" + response); return mapper.readValue(response, LightAttributes.class); } /** * Gets the current state of an individual light * <p/> * {@sample.xml ../../../doc/Hue-connector.xml.sample hue:get-group-state} * * @param groupId the identifier of the group to query state * * @return The complete state of a group * @throws IOException if there is a connection error or if the call returns an error response */ @Processor public GroupAttributes getGroupState(String groupId) throws IOException { WebResource resource = httpClient.resource(getBaseUri() + "/groups/" + groupId); String response = resource.get(String.class); if (response.contains("error")) { throw new IOException(response); } return mapper.readValue(response, GroupAttributes.class); } public final String getBaseUri() { return "http://" + ipAddress + "/api/" + username; } }