gurux.dlms.objects.GXDLMSClock Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gurux.dlms Show documentation
Show all versions of gurux.dlms Show documentation
gurux.dlms.java package is used to communicate with DLMS devices.
//
// --------------------------------------------------------------------------
// Gurux Ltd
//
//
//
// Filename: $HeadURL$
//
// Version: $Revision$,
// $Date$
// $Author$
//
// Copyright (c) Gurux Ltd
//
//---------------------------------------------------------------------------
//
// DESCRIPTION
//
// This file is a part of Gurux Device Framework.
//
// Gurux Device Framework is Open Source software; you can redistribute it
// and/or modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2 of the License.
// Gurux Device Framework 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.
//
// More information of Gurux products: https://www.gurux.org
//
// This code is licensed under the GNU General Public License v2.
// Full text may be retrieved at http://www.gnu.org/licenses/gpl-2.0.txt
//---------------------------------------------------------------------------
package gurux.dlms.objects;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TimeZone;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.xml.stream.XMLStreamException;
import gurux.dlms.GXByteBuffer;
import gurux.dlms.GXDLMSClient;
import gurux.dlms.GXDLMSSettings;
import gurux.dlms.GXDateTime;
import gurux.dlms.ValueEventArgs;
import gurux.dlms.enums.ClockStatus;
import gurux.dlms.enums.DataType;
import gurux.dlms.enums.DateTimeSkips;
import gurux.dlms.enums.ErrorCode;
import gurux.dlms.enums.ObjectType;
import gurux.dlms.internal.GXCommon;
import gurux.dlms.objects.enums.ClockBase;
/**
* Online help:
* https://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSClock
*/
public class GXDLMSClock extends GXDLMSObject implements IGXDLMSBase {
private ClockBase clockBase;
private int deviation;
private boolean enabled;
private GXDateTime end = new GXDateTime();
private java.util.Set status;
private GXDateTime begin = new GXDateTime();
private int timeZone;
private GXDateTime time = new GXDateTime();
/**
* Constructor.
*/
public GXDLMSClock() {
this("0.0.1.0.0.255", 0);
}
/**
* Constructor.
*
* @param ln
* Logical Name of the object.
*/
public GXDLMSClock(final String ln) {
this(ln, 0);
}
/**
* Constructor.
*
* @param ln
* Logical Name of the object.
* @param sn
* Short Name of the object.
*/
public GXDLMSClock(final String ln, final int sn) {
super(ObjectType.CLOCK, ln, sn);
status = new HashSet();
status.add(ClockStatus.OK);
deviation = 0;
java.util.Set value = new HashSet();
value.add(DateTimeSkips.MONTH);
value.add(DateTimeSkips.DAY);
begin.setSkip(value);
end.setSkip(begin.getSkip());
clockBase = ClockBase.NONE;
}
@Override
public final DataType getUIDataType(final int index) {
if (index == 2 || index == 5 || index == 6) {
return DataType.DATETIME;
}
return super.getUIDataType(index);
}
/**
* @return Time of COSEM Clock object.
*/
public final GXDateTime getTime() {
return time;
}
/**
* @param value
* Time of COSEM Clock object.
*/
public final void setTime(final GXDateTime value) {
time = value;
}
/**
* @param value
* Time of COSEM Clock object.
*/
public final void setTime(final Date value) {
time = new GXDateTime(value);
}
/**
* @param value
* Time of COSEM Clock object.
*/
public final void setTime(final java.util.Calendar value) {
time = new GXDateTime(value.getTime());
}
/**
* @return TimeZone of COSEM Clock object.
*/
public final int getTimeZone() {
return timeZone;
}
/**
* @param value
* TimeZone of COSEM Clock object.
*/
public final void setTimeZone(final int value) {
timeZone = value;
}
/**
* @return Status of COSEM Clock object.
*/
public final java.util.Set getStatus() {
return status;
}
/**
* @param value
* Status of COSEM Clock object.
*/
public final void setStatus(final java.util.Set value) {
status = value;
}
public final GXDateTime getBegin() {
return begin;
}
public final void setBegin(final GXDateTime value) {
begin = value;
}
public final GXDateTime getEnd() {
return end;
}
public final void setEnd(final GXDateTime value) {
end = value;
}
public final int getDeviation() {
return deviation;
}
public final void setDeviation(final int value) {
deviation = value;
}
public final boolean getEnabled() {
return enabled;
}
public final void setEnabled(final boolean value) {
enabled = value;
}
/**
* @return Clock base of COSEM Clock object.
*/
public final ClockBase getClockBase() {
return clockBase;
}
/**
* @param value
* Clock base of COSEM Clock object.
*/
public final void setClockBase(final ClockBase value) {
clockBase = value;
}
@Override
public final Object[] getValues() {
return new Object[] { getLogicalName(), getTime(), getTimeZone(), getStatus(), getBegin(),
getEnd(), getDeviation(), getEnabled(), getClockBase() };
}
/**
* @return Returns current time.
*/
public GXDateTime now() {
Calendar now = Calendar.getInstance();
GXDateTime tm = new GXDateTime(now);
if (timeZone == -1 || timeZone == -32768 || timeZone == 0x8000) {
tm.getSkip().add(DateTimeSkips.DEVIATION);
} else {
// If clock's time zone is different what user want's to use.
int offset = timeZone + now.getTimeZone().getRawOffset() / 60000;
if (offset != 0) {
TimeZone tz = GXDateTime.getTimeZone(timeZone, enabled);
if (tz != null) {
now = Calendar.getInstance(tz);
} else {
// Use current time zone if time zone is not found.
now = Calendar.getInstance();
}
tm.setMeterCalendar(now);
}
}
// If clock's daylight saving is active but user do not want to use it.
if (!enabled && now.getTimeZone().observesDaylightTime()) {
tm.getStatus().remove(ClockStatus.DAYLIGHT_SAVE_ACTIVE);
tm.getMeterCalendar().add(Calendar.MINUTE, -deviation);
}
return tm;
}
@Override
@SuppressWarnings("squid:S1168")
public final byte[] invoke(final GXDLMSSettings settings, final ValueEventArgs e) {
// Resets the value to the default value.
// The default value is an instance specific constant.
if (e.getIndex() == 1) {
GXDateTime dt = getTime();
java.util.Calendar tm = Calendar.getInstance();
tm.setTime(dt.getMeterCalendar().getTime());
int minutes = tm.get(java.util.Calendar.MINUTE);
if (minutes < 8) {
minutes = 0;
} else if (minutes < 23) {
minutes = 15;
} else if (minutes < 38) {
minutes = 30;
} else if (minutes < 53) {
minutes = 45;
} else {
minutes = 0;
tm.add(java.util.Calendar.HOUR_OF_DAY, 1);
}
tm.set(java.util.Calendar.MINUTE, minutes);
tm.set(java.util.Calendar.SECOND, 0);
tm.set(java.util.Calendar.MILLISECOND, 0);
dt.setMeterCalendar(tm);
setTime(dt);
} else if (e.getIndex() == 3) {
// Sets the meter's time to the nearest minute.
GXDateTime dt = getTime();
java.util.Calendar tm = Calendar.getInstance();
tm.setTime(dt.getMeterCalendar().getTime());
int s = tm.get(java.util.Calendar.SECOND);
if (s > 30) {
tm.add(java.util.Calendar.MINUTE, 1);
}
tm.set(java.util.Calendar.SECOND, 0);
tm.set(java.util.Calendar.MILLISECOND, 0);
dt.setMeterCalendar(tm);
setTime(dt);
} else if (e.getIndex() == 5) {
List> arr = (List>) e.getParameters();
// Presets the time to a new value (preset_time) and defines
// avalidity_interval within which the new time can be activated.
GXDateTime presetTime = (GXDateTime) GXDLMSClient.changeType((byte[]) arr.get(0),
DataType.DATETIME, e.getSettings());
// GXDateTime validityIntervalStart = (GXDateTime)
GXDLMSClient.changeType((byte[]) arr.get(1), DataType.DATETIME, e.getSettings());
// GXDateTime validityIntervalEnd = (GXDateTime)
GXDLMSClient.changeType((byte[]) arr.get(2), DataType.DATETIME, e.getSettings());
setTime(presetTime);
} else if (e.getIndex() == 6) {
// Shifts the time.
int shift = ((Number) e.getParameters()).intValue();
GXDateTime dt = getTime();
java.util.Calendar tm = Calendar.getInstance();
tm.setTime(dt.getMeterCalendar().getTime());
tm.add(java.util.Calendar.SECOND, shift);
dt.setMeterCalendar(tm);
setTime(dt);
} else {
e.setError(ErrorCode.READ_WRITE_DENIED);
}
return null;
}
/*
* Sets the meter's time to the nearest (+/-) quarter of an hour value
* (*:00, *:15, *:30, *:45).
*/
public final byte[][] adjustToQuarter(final GXDLMSClient client) throws InvalidKeyException,
NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException,
IllegalBlockSizeException, BadPaddingException, SignatureException {
return client.method(this, 1, 0, DataType.INT8);
}
/*
* Sets the meter's time to the nearest (+/-) starting point of a measuring
* period.
*/
public final byte[][] adjustToMeasuringPeriod(final GXDLMSClient client)
throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException,
InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException,
SignatureException {
return client.method(this, 2, 0, DataType.INT8);
}
/*
* Sets the meter's time to the nearest minute. If second_counter < 30 s, so
* second_counter is set to 0. If second_counter ³ 30 s, so second_counter
* is set to 0, and minute_counter and all depending clock values are
* incremented if necessary.
*/
public final byte[][] adjustToMinute(final GXDLMSClient client) throws InvalidKeyException,
NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException,
IllegalBlockSizeException, BadPaddingException, SignatureException {
return client.method(this, 3, 0, DataType.INT8);
}
/*
* This method is used in conjunction with the preset_adjusting_time method.
* If the meter's time lies between validity_interval_start and
* validity_interval_end, then time is set to preset_time.
*/
public final byte[][] adjustToPresetTime(final GXDLMSClient client) throws InvalidKeyException,
NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException,
IllegalBlockSizeException, BadPaddingException, SignatureException {
return client.method(this, 4, 0, DataType.INT8);
}
/*
* Presets the time to a new value (preset_time) and defines a
* validity_interval within which the new time can be activated.
*/
public final byte[][] presetAdjustingTime(final GXDLMSClient client, final Date presetTime,
final Date validityIntervalStart, final Date validityIntervalEnd)
throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException,
InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException,
SignatureException {
GXByteBuffer buff = new GXByteBuffer(44);
buff.setUInt8(DataType.STRUCTURE.getValue());
buff.setUInt8(3);
GXCommon.setData(null, buff, DataType.OCTET_STRING, presetTime);
GXCommon.setData(null, buff, DataType.OCTET_STRING, validityIntervalStart);
GXCommon.setData(null, buff, DataType.OCTET_STRING, validityIntervalEnd);
return client.method(this, 5, buff.array(), DataType.ARRAY);
}
/*
* Shifts the time by n (-900 <= n <= 900) s.
*/
public final byte[][] shiftTime(final GXDLMSClient client, final int forTime)
throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException,
InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException,
SignatureException {
if (forTime < -900 || forTime > 900) {
throw new IllegalArgumentException("Invalid shift time.");
}
return client.method(this, 6, forTime, DataType.INT16);
}
/*
* Returns collection of attributes to read. If attribute is static and
* already read or device is returned HW error it is not returned.
*/
@Override
public final int[] getAttributeIndexToRead(final boolean all) {
java.util.ArrayList attributes = new java.util.ArrayList();
// LN is static and read only once.
if (all || getLogicalName() == null || getLogicalName().compareTo("") == 0) {
attributes.add(1);
}
// Time
if (all || canRead(2)) {
attributes.add(2);
}
// TimeZone
if (all || !isRead(3)) {
attributes.add(3);
}
// Status
if (all || canRead(4)) {
attributes.add(4);
}
// Begin
if (all || !isRead(5)) {
attributes.add(5);
}
// End
if (all || !isRead(6)) {
attributes.add(6);
}
// Deviation
if (all || !isRead(7)) {
attributes.add(7);
}
// Enabled
if (all || !isRead(8)) {
attributes.add(8);
}
// ClockBase
if (all || !isRead(9)) {
attributes.add(9);
}
return GXDLMSObjectHelpers.toIntArray(attributes);
}
/*
* Returns amount of attributes.
*/
@Override
public final int getAttributeCount() {
return 9;
}
/*
* Returns amount of methods.
*/
@Override
public final int getMethodCount() {
return 6;
}
@Override
public final DataType getDataType(final int index) {
switch (index) {
case 1:
return DataType.OCTET_STRING;
case 2:
return DataType.OCTET_STRING;
case 3:
return DataType.INT16;
case 4:
return DataType.UINT8;
case 5:
return DataType.OCTET_STRING;
case 6:
return DataType.OCTET_STRING;
case 7:
return DataType.INT8;
case 8:
return DataType.BOOLEAN;
case 9:
return DataType.ENUM;
default:
throw new IllegalArgumentException("getDataType failed. Invalid attribute index.");
}
}
/*
* Returns value of given attribute.
*/
@Override
public final Object getValue(final GXDLMSSettings settings, final ValueEventArgs e) {
switch (e.getIndex()) {
case 1:
return GXCommon.logicalNameToBytes(getLogicalName());
case 2:
return getTime();
case 3:
return getTimeZone();
case 4:
return ClockStatus.toInteger(status);
case 5:
return getBegin();
case 6:
return getEnd();
case 7:
return getDeviation();
case 8:
return getEnabled();
case 9:
return getClockBase().ordinal();
default:
e.setError(ErrorCode.READ_WRITE_DENIED);
break;
}
return null;
}
/*
* Set value of given attribute.
*/
@Override
public final void setValue(final GXDLMSSettings settings, final ValueEventArgs e) {
switch (e.getIndex()) {
case 1:
setLogicalName(GXCommon.toLogicalName(e.getValue()));
break;
case 2:
if (e.getValue() == null) {
setTime(new GXDateTime());
} else {
GXDateTime tmp;
if (e.getValue() instanceof byte[]) {
tmp = (GXDateTime) GXDLMSClient.changeType((byte[]) e.getValue(),
DataType.DATETIME, e.getSettings());
} else {
tmp = (GXDateTime) e.getValue();
}
setTime(tmp);
}
break;
case 3:
if (e.getValue() == null) {
setTimeZone(0);
} else {
setTimeZone(((Number) e.getValue()).intValue());
}
break;
case 4:
if (e.getValue() == null) {
Set val = new HashSet();
val.add(ClockStatus.OK);
setStatus(val);
} else {
setStatus(ClockStatus.forValue(((Number) e.getValue()).intValue()));
}
break;
case 5:
if (e.getValue() == null) {
setBegin(new GXDateTime());
} else if (e.getValue() instanceof byte[]) {
GXDateTime tmp;
tmp = (GXDateTime) GXDLMSClient.changeType((byte[]) e.getValue(), DataType.DATETIME,
e.getSettings());
setBegin(tmp);
} else {
setBegin((GXDateTime) e.getValue());
}
break;
case 6:
if (e.getValue() == null) {
setEnd(new GXDateTime());
} else if (e.getValue() instanceof byte[]) {
GXDateTime tmp;
tmp = (GXDateTime) GXDLMSClient.changeType((byte[]) e.getValue(), DataType.DATETIME,
e.getSettings());
setEnd(tmp);
} else {
setEnd((GXDateTime) e.getValue());
}
break;
case 7:
if (e.getValue() == null) {
setDeviation(0);
} else {
setDeviation(((Number) e.getValue()).intValue());
}
break;
case 8:
if (e.getValue() == null) {
setEnabled(false);
} else {
setEnabled(((Boolean) e.getValue()).booleanValue());
}
break;
case 9:
if (e.getValue() == null) {
setClockBase(ClockBase.NONE);
} else {
setClockBase(ClockBase.values()[((Number) e.getValue()).intValue()]);
}
break;
default:
e.setError(ErrorCode.READ_WRITE_DENIED);
break;
}
}
@Override
public final void load(final GXXmlReader reader) throws XMLStreamException {
time = reader.readElementContentAsDateTime("Time");
timeZone = reader.readElementContentAsInt("TimeZone");
status = ClockStatus.forValue(reader.readElementContentAsInt("Status"));
begin = reader.readElementContentAsDateTime("Begin");
end = reader.readElementContentAsDateTime("End");
deviation = reader.readElementContentAsInt("Deviation");
enabled = reader.readElementContentAsInt("Enabled") != 0;
clockBase = ClockBase.values()[reader.readElementContentAsInt("ClockBase")];
}
@Override
public final void save(final GXXmlWriter writer) throws XMLStreamException {
writer.writeElementString("Time", time);
writer.writeElementString("TimeZone", timeZone);
writer.writeElementString("Status", ClockStatus.toInteger(status));
writer.writeElementString("Begin", begin);
writer.writeElementString("End", end);
writer.writeElementString("Deviation", deviation);
writer.writeElementString("Enabled", enabled);
writer.writeElementString("ClockBase", clockBase.ordinal());
}
@Override
public final void postLoad(final GXXmlReader reader) {
// Not needed for this object.
}
@Override
public String[] getNames() {
return new String[] { "Logical Name", "Time", "Time Zone", "Status", "Begin", "End",
"Deviation", "Enabled", "Clock Base" };
}
@Override
public String[] getMethodNames() {
return new String[] { "Adjust to quarter", "Adjust to measuring period", "Adjust to minute",
"Adjust to preset time", "Preset adjusting time", "Shift time" };
}
}