li.klass.fhem.service.intent.DeviceIntentService.java Source code

Java tutorial

Introduction

Here is the source code for li.klass.fhem.service.intent.DeviceIntentService.java

Source

/*
 * AndFHEM - Open Source Android application to control a FHEM home automation
 * server.
 *
 * Copyright (c) 2011, Matthias Klass or third-party contributors as
 * indicated by the @author tags or express copyright attribution
 * statements applied by the authors.  All third-party contributions are
 * distributed under license by Red Hat Inc.
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU GENERAL PUBLIC LICENSE, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU GENERAL PUBLIC LICENSE
 * for more details.
 *
 * You should have received a copy of the GNU GENERAL PUBLIC LICENSE
 * along with this distribution; if not, write to:
 *   Free Software Foundation, Inc.
 *   51 Franklin Street, Fifth Floor
 *   Boston, MA  02110-1301  USA
 */

package li.klass.fhem.service.intent;

import android.content.Intent;
import android.os.Bundle;
import android.os.ResultReceiver;
import android.util.Log;

import com.google.common.base.Optional;

import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.List;

import javax.inject.Inject;

import li.klass.fhem.appwidget.service.AppWidgetUpdateService;
import li.klass.fhem.constants.Actions;
import li.klass.fhem.constants.BundleExtraKeys;
import li.klass.fhem.constants.ResultCodes;
import li.klass.fhem.domain.FHTDevice;
import li.klass.fhem.domain.GCMSendDevice;
import li.klass.fhem.domain.WOLDevice;
import li.klass.fhem.domain.core.DimmableDevice;
import li.klass.fhem.domain.core.FhemDevice;
import li.klass.fhem.domain.core.ToggleableDevice;
import li.klass.fhem.domain.fht.FHTMode;
import li.klass.fhem.domain.heating.ComfortTempDevice;
import li.klass.fhem.domain.heating.DesiredTempDevice;
import li.klass.fhem.domain.heating.EcoTempDevice;
import li.klass.fhem.domain.heating.HeatingDevice;
import li.klass.fhem.domain.heating.WindowOpenTempDevice;
import li.klass.fhem.service.CommandExecutionService;
import li.klass.fhem.service.NotificationService;
import li.klass.fhem.service.device.AtService;
import li.klass.fhem.service.device.DeviceService;
import li.klass.fhem.service.device.DimmableDeviceService;
import li.klass.fhem.service.device.FHTService;
import li.klass.fhem.service.device.GCMSendDeviceService;
import li.klass.fhem.service.device.GenericDeviceService;
import li.klass.fhem.service.device.HeatingService;
import li.klass.fhem.service.device.ToggleableService;
import li.klass.fhem.service.device.WOLService;
import li.klass.fhem.service.graph.GraphEntry;
import li.klass.fhem.service.graph.GraphService;
import li.klass.fhem.service.graph.gplot.GPlotSeries;
import li.klass.fhem.service.graph.gplot.SvgGraphDefinition;
import li.klass.fhem.service.room.RoomListService;

import static li.klass.fhem.constants.Actions.DEVICE_DELETE;
import static li.klass.fhem.constants.Actions.DEVICE_DIM;
import static li.klass.fhem.constants.Actions.DEVICE_GRAPH;
import static li.klass.fhem.constants.Actions.DEVICE_MOVE_ROOM;
import static li.klass.fhem.constants.Actions.DEVICE_REFRESH_STATE;
import static li.klass.fhem.constants.Actions.DEVICE_REFRESH_VALUES;
import static li.klass.fhem.constants.Actions.DEVICE_RENAME;
import static li.klass.fhem.constants.Actions.DEVICE_RESET_WEEK_PROFILE;
import static li.klass.fhem.constants.Actions.DEVICE_SET_ALIAS;
import static li.klass.fhem.constants.Actions.DEVICE_SET_COMFORT_TEMPERATURE;
import static li.klass.fhem.constants.Actions.DEVICE_SET_DAY_TEMPERATURE;
import static li.klass.fhem.constants.Actions.DEVICE_SET_DESIRED_TEMPERATURE;
import static li.klass.fhem.constants.Actions.DEVICE_SET_ECO_TEMPERATURE;
import static li.klass.fhem.constants.Actions.DEVICE_SET_MODE;
import static li.klass.fhem.constants.Actions.DEVICE_SET_NIGHT_TEMPERATURE;
import static li.klass.fhem.constants.Actions.DEVICE_SET_STATE;
import static li.klass.fhem.constants.Actions.DEVICE_SET_SUB_STATE;
import static li.klass.fhem.constants.Actions.DEVICE_SET_WEEK_PROFILE;
import static li.klass.fhem.constants.Actions.DEVICE_SET_WINDOW_OPEN_TEMPERATURE;
import static li.klass.fhem.constants.Actions.DEVICE_TIMER_MODIFY;
import static li.klass.fhem.constants.Actions.DEVICE_TIMER_NEW;
import static li.klass.fhem.constants.Actions.DEVICE_TOGGLE_STATE;
import static li.klass.fhem.constants.Actions.DEVICE_WIDGET_TOGGLE;
import static li.klass.fhem.constants.Actions.GCM_ADD_SELF;
import static li.klass.fhem.constants.Actions.GCM_REMOVE_ID;
import static li.klass.fhem.constants.Actions.RESEND_LAST_FAILED_COMMAND;
import static li.klass.fhem.constants.BundleExtraKeys.DEVICE_GRAPH_ENTRY_MAP;
import static li.klass.fhem.constants.BundleExtraKeys.STATE_NAME;
import static li.klass.fhem.constants.BundleExtraKeys.STATE_VALUE;
import static li.klass.fhem.service.intent.ConvenientIntentService.STATE.DONE;
import static li.klass.fhem.service.intent.ConvenientIntentService.STATE.ERROR;
import static li.klass.fhem.service.intent.ConvenientIntentService.STATE.SUCCESS;
import static li.klass.fhem.service.room.RoomListService.RemoteUpdateRequired.REQUIRED;

public class DeviceIntentService extends ConvenientIntentService {

    @Inject
    RoomListService roomListService;
    @Inject
    FHTService fhtService;
    @Inject
    HeatingService heatingService;
    @Inject
    DeviceService deviceService;
    @Inject
    GenericDeviceService genericDeviceService;
    @Inject
    GCMSendDeviceService gcmSendDeviceService;
    @Inject
    CommandExecutionService commandExecutionService;
    @Inject
    AtService atService;
    @Inject
    WOLService wolService;
    @Inject
    DimmableDeviceService dimmableDeviceService;
    @Inject
    ToggleableService toggleableService;
    @Inject
    GraphService graphService;
    @Inject
    NotificationService notificationService;

    private static final Logger LOG = LoggerFactory.getLogger(DeviceIntentService.class);

    public DeviceIntentService() {
        super(DeviceIntentService.class.getName());
    }

    @Override
    protected STATE handleIntent(Intent intent, long updatePeriod, ResultReceiver resultReceiver) {

        if (roomListService.updateRoomDeviceListIfRequired(intent, updatePeriod, this) == REQUIRED) {
            return DONE;
        }

        String deviceName = intent.getStringExtra(BundleExtraKeys.DEVICE_NAME);
        Optional<FhemDevice> deviceOptional = roomListService.getDeviceForName(deviceName, this);
        if (!deviceOptional.isPresent()) {
            LOG.info("handleIntent() - cannot find device for {}", deviceName);
        }
        FhemDevice device = deviceOptional.orNull();

        Log.d(DeviceIntentService.class.getName(), intent.getAction());
        String action = intent.getAction();

        STATE result = STATE.SUCCESS;
        if (DEVICE_GRAPH.equals(action)) {
            result = graphIntent(intent, device, resultReceiver);
        } else if (DEVICE_TOGGLE_STATE.equals(action)) {
            result = toggleIntent(device);
        } else if (DEVICE_SET_STATE.equals(action)) {
            result = setStateIntent(intent, device);
        } else if (DEVICE_DIM.equals(action)) {
            result = dimIntent(intent, device);
        } else if (DEVICE_SET_DAY_TEMPERATURE.equals(action)) {
            double dayTemperature = intent.getDoubleExtra(BundleExtraKeys.DEVICE_TEMPERATURE, -1);
            fhtService.setDayTemperature((FHTDevice) device, dayTemperature, this);
        } else if (DEVICE_SET_NIGHT_TEMPERATURE.equals(action)) {
            double nightTemperature = intent.getDoubleExtra(BundleExtraKeys.DEVICE_TEMPERATURE, -1);
            fhtService.setNightTemperature((FHTDevice) device, nightTemperature, this);
        } else if (DEVICE_SET_MODE.equals(action)) {
            if (device instanceof FHTDevice) {
                FHTMode mode = (FHTMode) intent.getSerializableExtra(BundleExtraKeys.DEVICE_MODE);
                double desiredTemperature = intent.getDoubleExtra(BundleExtraKeys.DEVICE_TEMPERATURE,
                        FHTDevice.MINIMUM_TEMPERATURE);
                int holiday1 = intent.getIntExtra(BundleExtraKeys.DEVICE_HOLIDAY1, -1);
                int holiday2 = intent.getIntExtra(BundleExtraKeys.DEVICE_HOLIDAY2, -1);

                fhtService.setMode((FHTDevice) device, mode, desiredTemperature, holiday1, holiday2, this);
            } else if (device instanceof HeatingDevice) {
                Enum mode = (Enum) intent.getSerializableExtra(BundleExtraKeys.DEVICE_MODE);
                HeatingDevice heatingDevice = (HeatingDevice) device;

                heatingService.setMode(heatingDevice, mode, this);
            }

        } else if (DEVICE_SET_WEEK_PROFILE.equals(action)) {
            if (!(device instanceof HeatingDevice))
                return ERROR;
            heatingService.setWeekProfileFor((HeatingDevice) device, this);

        } else if (DEVICE_SET_WINDOW_OPEN_TEMPERATURE.equals(action)) {
            if (!(device instanceof WindowOpenTempDevice))
                return SUCCESS;

            double temperature = intent.getDoubleExtra(BundleExtraKeys.DEVICE_TEMPERATURE, -1);
            heatingService.setWindowOpenTemp((WindowOpenTempDevice) device, temperature, this);

        } else if (DEVICE_SET_DESIRED_TEMPERATURE.equals(action)) {
            double temperature = intent.getDoubleExtra(BundleExtraKeys.DEVICE_TEMPERATURE, -1);
            if (device instanceof DesiredTempDevice) {
                heatingService.setDesiredTemperature((DesiredTempDevice) device, temperature, this);
            }

        } else if (DEVICE_SET_COMFORT_TEMPERATURE.equals(action)) {
            double temperature = intent.getDoubleExtra(BundleExtraKeys.DEVICE_TEMPERATURE, -1);
            if (device instanceof DesiredTempDevice) {
                heatingService.setComfortTemperature((ComfortTempDevice) device, temperature, this);
            }

        } else if (DEVICE_SET_ECO_TEMPERATURE.equals(action)) {
            double temperature = intent.getDoubleExtra(BundleExtraKeys.DEVICE_TEMPERATURE, -1);
            if (device instanceof DesiredTempDevice) {
                heatingService.setEcoTemperature((EcoTempDevice) device, temperature, this);
            }

        } else if (DEVICE_RESET_WEEK_PROFILE.equals(action)) {
            if (!(device instanceof HeatingDevice))
                return ERROR;
            heatingService.resetWeekProfile((HeatingDevice) device);

        } else if (DEVICE_REFRESH_VALUES.equals(action)) {
            fhtService.refreshValues((FHTDevice) device, this);

        } else if (DEVICE_RENAME.equals(action)) {
            String newName = intent.getStringExtra(BundleExtraKeys.DEVICE_NEW_NAME);
            deviceService.renameDevice(device, newName, this);
            notificationService.rename(device.getName(), newName, this);

        } else if (DEVICE_DELETE.equals(action)) {
            deviceService.deleteDevice(device, this);

        } else if (DEVICE_MOVE_ROOM.equals(action)) {
            String newRoom = intent.getStringExtra(BundleExtraKeys.DEVICE_NEW_ROOM);
            deviceService.moveDevice(device, newRoom, this);

        } else if (DEVICE_SET_ALIAS.equals(action)) {
            String newAlias = intent.getStringExtra(BundleExtraKeys.DEVICE_NEW_ALIAS);
            deviceService.setAlias(device, newAlias, this);

        } else if (DEVICE_REFRESH_STATE.equals(action)) {
            wolService.requestRefreshState((WOLDevice) device, this);
        } else if (DEVICE_WIDGET_TOGGLE.equals(action)) {
            result = toggleIntent(device);

        } else if (DEVICE_TIMER_MODIFY.equals(action)) {
            processTimerIntent(intent, true);

        } else if (DEVICE_TIMER_NEW.equals(action)) {
            processTimerIntent(intent, false);

        } else if (DEVICE_SET_SUB_STATE.equals(action)) {
            String name = intent.getStringExtra(STATE_NAME);
            String value = intent.getStringExtra(STATE_VALUE);

            genericDeviceService.setSubState(device, name, value, this);

        } else if (GCM_ADD_SELF.equals(action)) {
            gcmSendDeviceService.addSelf((GCMSendDevice) device, this);

        } else if (GCM_REMOVE_ID.equals(action)) {
            String registrationId = intent.getStringExtra(BundleExtraKeys.GCM_REGISTRATION_ID);
            gcmSendDeviceService.removeRegistrationId((GCMSendDevice) device, registrationId, this);

        } else if (RESEND_LAST_FAILED_COMMAND.equals(action)) {

            String lastFailedCommand = commandExecutionService.getLastFailedCommand();
            if ("xmllist".equalsIgnoreCase(lastFailedCommand)) {
                Intent updateIntent = new Intent(Actions.DO_UPDATE);
                updateIntent.putExtra(BundleExtraKeys.DO_REFRESH, true);
                sendBroadcast(updateIntent);
            } else {
                commandExecutionService.resendLastFailedCommand(this);
            }
        }

        Intent redrawWidgetsIntent = new Intent(Actions.REDRAW_ALL_WIDGETS);
        redrawWidgetsIntent.setClass(this, AppWidgetUpdateService.class);
        startService(redrawWidgetsIntent);

        return result;
    }

    /**
     * Find out graph data for a given device and notify the result receiver with the read graph data
     *
     * @param intent         received intent
     * @param device         device to read the graph data
     * @param resultReceiver receiver to notify on result
     * @return success?
     */
    private STATE graphIntent(Intent intent, FhemDevice device, ResultReceiver resultReceiver) {
        SvgGraphDefinition graphDefinition = (SvgGraphDefinition) intent
                .getSerializableExtra(BundleExtraKeys.DEVICE_GRAPH_DEFINITION);
        DateTime startDate = (DateTime) intent.getSerializableExtra(BundleExtraKeys.START_DATE);
        DateTime endDate = (DateTime) intent.getSerializableExtra(BundleExtraKeys.END_DATE);

        HashMap<GPlotSeries, List<GraphEntry>> graphData = graphService.getGraphData(device, graphDefinition,
                startDate, endDate, this);
        sendSingleExtraResult(resultReceiver, ResultCodes.SUCCESS, DEVICE_GRAPH_ENTRY_MAP, graphData);
        return STATE.DONE;
    }

    /**
     * Toggle a device and notify the result receiver
     *
     * @param device device to toggle
     * @return success?
     */
    private STATE toggleIntent(FhemDevice device) {
        if (device instanceof ToggleableDevice && ((ToggleableDevice) device).supportsToggle()) {
            toggleableService.toggleState((ToggleableDevice) device, this);
            return SUCCESS;
        } else {
            return ERROR;
        }
    }

    /**
     * Set the state of a device and notify the result receiver
     *
     * @param intent received intent
     * @param device device to set the state on
     * @return success ?
     */
    private STATE setStateIntent(Intent intent, FhemDevice device) {
        String targetState = intent.getStringExtra(BundleExtraKeys.DEVICE_TARGET_STATE);
        int timesToSend = intent.getIntExtra(BundleExtraKeys.TIMES_TO_SEND, 1);

        for (int i = 0; i < timesToSend; i++) {
            genericDeviceService.setState(device, targetState, this);
        }

        return STATE.SUCCESS;
    }

    /**
     * Dim a device and notify the result receiver
     *
     * @param intent received intent
     * @param device device to dim
     * @return success?
     */
    private STATE dimIntent(Intent intent, FhemDevice device) {
        int dimProgress = intent.getIntExtra(BundleExtraKeys.DEVICE_DIM_PROGRESS, -1);
        if (device instanceof DimmableDevice) {
            dimmableDeviceService.dim((DimmableDevice) device, dimProgress, this);
            return STATE.SUCCESS;
        }
        return STATE.ERROR;
    }

    private STATE processTimerIntent(Intent intent, boolean isModify) {
        Bundle extras = intent.getExtras();

        assert extras != null;

        String targetDeviceName = extras.getString(BundleExtraKeys.TIMER_TARGET_DEVICE_NAME);
        String targetState = extras.getString(BundleExtraKeys.TIMER_TARGET_STATE);
        int hour = extras.getInt(BundleExtraKeys.TIMER_HOUR, 0);
        int minute = extras.getInt(BundleExtraKeys.TIMER_MINUTE, 0);
        int second = extras.getInt(BundleExtraKeys.TIMER_SECOND, 0);
        String repetition = extras.getString(BundleExtraKeys.TIMER_REPETITION);
        String type = extras.getString(BundleExtraKeys.TIMER_TYPE);
        String stateAppendix = extras.getString(BundleExtraKeys.TIMER_TARGET_STATE_APPENDIX);
        String timerName = extras.getString(BundleExtraKeys.DEVICE_NAME);
        boolean isActive = extras.getBoolean(BundleExtraKeys.TIMER_IS_ACTIVE);

        if (isModify) {
            atService.modify(timerName, hour, minute, second, repetition, type, targetDeviceName, targetState,
                    stateAppendix, isActive, this);
        } else {
            atService.createNew(timerName, hour, minute, second, repetition, type, targetDeviceName, targetState,
                    stateAppendix, isActive, this);
        }

        return SUCCESS;
    }
}