public override void ConnectClients()
        {
            base.ConnectClients();

            Assert.AreEqual(XmppState.Connected, this.client1.State);
            Assert.AreEqual(XmppState.Connected, this.client2.State);

            this.sensorClient = new SensorClient(this.client1);
            this.sensorServer = new SensorServer(this.client2, true);

            this.temp = 12.3;

            this.sensorServer.OnExecuteReadoutRequest += (sender, e) =>
            {
                DateTime Now = DateTime.Now;

                e.ReportFields(true,
                               new QuantityField(ThingReference.Empty, Now, "Temperature", this.temp, 1, "C", FieldType.Momentary, FieldQoS.AutomaticReadout),
                               new BooleanField(ThingReference.Empty, Now, "Bool", true, FieldType.Momentary, FieldQoS.AutomaticReadout),
                               new DateField(ThingReference.Empty, Now, "Date", DateTime.Today, FieldType.Momentary, FieldQoS.AutomaticReadout),
                               new DateTimeField(ThingReference.Empty, Now, "DateTime", Now, FieldType.Momentary, FieldQoS.AutomaticReadout),
                               new DurationField(ThingReference.Empty, Now, "Duration", new Duration(true, 1, 2, 3, 4, 5, 6), FieldType.Momentary, FieldQoS.AutomaticReadout),
                               new EnumField(ThingReference.Empty, Now, "Enum", TypeCode.Boolean, FieldType.Momentary, FieldQoS.AutomaticReadout),
                               new Int32Field(ThingReference.Empty, Now, "Int32", int.MinValue, FieldType.Momentary, FieldQoS.AutomaticReadout),
                               new Int64Field(ThingReference.Empty, Now, "Int64", long.MinValue, FieldType.Momentary, FieldQoS.AutomaticReadout),
                               new StringField(ThingReference.Empty, Now, "String", "Hello world.", FieldType.Momentary, FieldQoS.AutomaticReadout),
                               new TimeField(ThingReference.Empty, Now, "Time", Now.TimeOfDay, FieldType.Momentary, FieldQoS.AutomaticReadout));

                return(Task.CompletedTask);
            };
        }
Beispiel #2
0
        private void Init(params ISniffer[] Sniffers)
        {
            if (!string.IsNullOrEmpty(this.passwordHash))
            {
                this.client = new XmppClient(this.host, this.port, this.account, this.passwordHash, this.passwordHashMethod, "en", typeof(App).Assembly);
            }
            else
            {
                this.client = new XmppClient(this.host, this.port, this.account, this.password, "en", typeof(App).Assembly);
            }

            if (Sniffers != null)
            {
                this.client.AddRange(Sniffers);
            }

            this.client.TrustServer            = this.trustCertificate;
            this.client.OnStateChanged        += new StateChangedEventHandler(Client_OnStateChanged);
            this.client.OnError               += new XmppExceptionEventHandler(Client_OnError);
            this.client.OnPresence            += new PresenceEventHandler(Client_OnPresence);
            this.client.OnPresenceSubscribe   += new PresenceEventHandler(Client_OnPresenceSubscribe);
            this.client.OnPresenceUnsubscribe += new PresenceEventHandler(Client_OnPresenceUnsubscribe);
            this.client.OnRosterItemAdded     += new RosterItemEventHandler(Client_OnRosterItemUpdated);
            this.client.OnRosterItemRemoved   += new RosterItemEventHandler(Client_OnRosterItemRemoved);
            this.client.OnRosterItemUpdated   += new RosterItemEventHandler(Client_OnRosterItemUpdated);
            this.connectionTimer               = new Timer(this.CheckConnection, null, 60000, 60000);

            this.client.SetPresence(Availability.Chat);

            this.sensorClient       = new SensorClient(this.client);
            this.controlClient      = new ControlClient(this.client);
            this.concentratorClient = new ConcentratorClient(this.client);

            this.client.Connect();
        }
Beispiel #3
0
        private void Dashboard_Load(object sender, EventArgs e)
        {
            sensorUILogger = new SensorUILogger(MainLog, RequestLog);

            try
            {
                sensor = new SensorClient(Username, IPaddress, Port, DataProvider, WebService, sensorUILogger);

                if (sensor == null || sensor.SensorWorking == false)
                {
                    MessageBox.Show("Unable to create/start sensor with given data.");
                    Dispose();
                }
                else
                {
                    userAddressBindingSource.DataSource = sensor.NeighborSensor;

                    SensorName.Text = sensor.Username;
                    IP.Text         = $"{sensor.IPaddress}:{sensor.Port}";

                    Text = $"Sensor Dashboard - {sensor.Username} - {sensor.IPaddress}:{sensor.Port}";
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Unable to create/start sensor with given data." + Environment.NewLine + $"Exception: {ex.Message}");
                Dispose();
            }
        }
Beispiel #4
0
        public override void Dispose()
        {
            base.Dispose();

            if (this.connectionTimer != null)
            {
                this.connectionTimer.Dispose();
                this.connectionTimer = null;
            }

            if (this.sensorClient != null)
            {
                this.sensorClient.Dispose();
                this.sensorClient = null;
            }

            if (this.controlClient != null)
            {
                this.controlClient.Dispose();
                this.controlClient = null;
            }

            if (this.concentratorClient != null)
            {
                this.concentratorClient.Dispose();
                this.concentratorClient = null;
            }

            if (this.client != null)
            {
                XmppClient Client = this.client;
                this.client = null;
                Client.Dispose();
            }
        }
Beispiel #5
0
        /// <summary>
        /// Adds the extension to the client.
        /// </summary>
        /// <param name="Instance">Actor instance.</param>
        /// <param name="Client">XMPP Client</param>
        public override Task Add(IActor Instance, Waher.Networking.XMPP.XmppClient Client)
        {
            SensorClient Extension = new SensorClient(Client);

            Client.SetTag("SensorClient", Extension);

            return(Task.CompletedTask);
        }
        /// <summary>
        /// Adds the extension to the client.
        /// </summary>
        /// <param name="Instance">Actor instance.</param>
        /// <param name="Client">XMPP Client</param>
        /// <returns>Extension object.</returns>
        public override Task <object> Add(IActor Instance, Waher.Networking.XMPP.XmppClient Client)
        {
            SensorClient Extension = new SensorClient(Client);

            Client.SetTag("SensorClient", Extension);

            return(Task.FromResult <object>(Extension));
        }
Beispiel #7
0
        public void Load(XmlDocument Xml, string FileName)
        {
            XmlElement E;

            XSL.Validate(FileName, Xml, sensorDataRoot, sensorDataNamespace, schema1, schema2);

            this.SensorDataListView.Items.Clear();
            this.nodes.Clear();
            this.failed.Clear();

            this.StateLabel.Content       = XML.Attribute(Xml.DocumentElement, "state", string.Empty);
            this.NodesOkLabel.Content     = XML.Attribute(Xml.DocumentElement, "nodesOk", string.Empty);
            this.NodesFailedLabel.Content = XML.Attribute(Xml.DocumentElement, "nodesFailed", string.Empty);
            this.NodesTotalLabel.Content  = XML.Attribute(Xml.DocumentElement, "nodesTotal", string.Empty);
            this.FieldsLabel.Content      = XML.Attribute(Xml.DocumentElement, "fields", string.Empty);

            foreach (XmlNode N in Xml.DocumentElement.ChildNodes)
            {
                E = N as XmlElement;
                if (E is null)
                {
                    continue;
                }

                switch (E.LocalName)
                {
                case "resp":
                    Tuple <List <Field>, List <ThingError> > Response = SensorClient.ParseFields(E, out bool _);

                    if (Response.Item1 != null)
                    {
                        foreach (Field Field in Response.Item1)
                        {
                            this.nodes[Field.Thing.Key] = true;
                            this.SensorDataListView.Items.Add(new FieldItem(Field));
                        }
                    }

                    if (Response.Item2 != null)
                    {
                        foreach (ThingError Error in Response.Item2)
                        {
                            string Key = Error.Key;
                            this.failed[Key] = true;
                            this.nodes[Key]  = true;
                        }
                    }

                    this.NodesFailedLabel.Content = this.failed.Count.ToString();
                    this.NodesTotalLabel.Content  = this.nodes.Count.ToString();

                    break;
                }
            }
        }
Beispiel #8
0
        static void Main(string[] args)
        {
            // Creating SensorClient performs automatically 'subscribe' action
            sc = new SensorClient("jl2", "user3", "bathstudent");
            sc.SensorClientCreateEvent += new SensorClientCreateEventHandler(sc_SensorClientCreateEvent);

            while (true)
            {
                // no-op
            }
        }
Beispiel #9
0
 /// <summary>
 /// Manages a sensor data client request.
 /// </summary>
 /// <param name="Id">Request identity.</param>
 /// <param name="SensorClient">Sensor client object.</param>
 /// <param name="RemoteJID">JID of the other side of the conversation in the sensor data readout.</param>
 /// <param name="Actor">Actor causing the request to be made.</param>
 /// <param name="Nodes">Array of nodes to read. Can be null or empty, if reading a sensor that is not a concentrator.</param>
 /// <param name="Types">Field Types to read.</param>
 /// <param name="FieldRules">Fields to read.</param>
 /// <param name="MinInterval">Smallest interval for reporting events. Events are not reported more often than this limit.</param>
 /// <param name="MaxInterval">Largest interval for reporting events. Events are not reported less often than this limit.</param>
 /// <param name="MaxAge">Maximum age of historical data.</param>
 /// <param name="ServiceToken">Optional service token, as defined in XEP-0324.</param>
 /// <param name="DeviceToken">Optional device token, as defined in XEP-0324.</param>
 /// <param name="UserToken">Optional user token, as defined in XEP-0324.</param>
 internal SensorDataSubscriptionRequest(string Id, SensorClient SensorClient, string RemoteJID, string Actor, ThingReference[] Nodes,
                                        FieldType Types, FieldSubscriptionRule[] FieldRules, Duration MinInterval, Duration MaxInterval, Duration MaxAge, string ServiceToken,
                                        string DeviceToken, string UserToken)
     : base(Id, SensorClient, RemoteJID, Actor, Nodes, Types, ExtractFieldNames(FieldRules),
            DateTime.MinValue, DateTime.MaxValue, DateTime.MinValue, ServiceToken, DeviceToken, UserToken)
 {
     this.minInterval = MinInterval;
     this.maxInterval = MaxInterval;
     this.maxAge      = MaxAge;
     this.fieldRules  = FieldRules;
 }
Beispiel #10
0
        public override SensorDataClientRequest StartSensorDataFullReadout()
        {
            XmppAccountNode XmppAccountNode = this.XmppAccountNode;
            SensorClient    SensorClient;

            if (XmppAccountNode != null && (SensorClient = XmppAccountNode.SensorClient) != null)
            {
                return(SensorClient.RequestReadout(this.RosterItem.LastPresenceFullJid, FieldType.All));
            }
            else
            {
                throw new NotSupportedException();
            }
        }
Beispiel #11
0
        public override SensorDataClientRequest StartSensorDataMomentaryReadout()
        {
            XmppAccountNode XmppAccountNode = this.XmppAccountNode;
            SensorClient    SensorClient;

            if (XmppAccountNode != null && (SensorClient = XmppAccountNode.SensorClient) != null)
            {
                return(SensorClient.RequestReadout(this.RosterItem.LastPresenceFullJid, FieldType.Momentary));
            }
            else
            {
                return(null);
            }
        }
        private void AddFeatures()
        {
            this.xmppClient.OnError += (Sender, ex) =>
            {
                Console.WriteLine("Error ", ex);
                return(Task.CompletedTask);
            };

            this.xmppClient.OnPasswordChanged += (Sender, e) =>
            {
                Console.WriteLine("Password changed.", this.xmppClient.BareJID);
            };

            this.xmppClient.OnPresenceSubscribe += (Sender, e) =>
            {
                Console.WriteLine("Accepting friendship request.", this.xmppClient.BareJID, e.From);
                e.Accept();
                return(Task.CompletedTask);
            };

            this.xmppClient.OnPresenceUnsubscribe += (Sender, e) =>
            {
                Console.WriteLine("Friendship removed.", this.xmppClient.BareJID, e.From);
                e.Accept();
                return(Task.CompletedTask);
            };

            this.xmppClient.OnPresenceSubscribed += (Sender, e) =>
            {
                Console.WriteLine("Friendship request accepted. " + this.xmppClient.BareJID + " " + e.From);

                if (string.Compare(e.FromBareJID, this.sensorJid, true) == 0)
                {
                    this.SubscribeToSensorData();
                }

                return(Task.CompletedTask);
            };

            this.xmppClient.OnPresenceUnsubscribed += (Sender, e) =>
            {
                Console.WriteLine("Friendship removal accepted.", this.xmppClient.BareJID, e.From);
                return(Task.CompletedTask);
            };

            this.xmppClient.OnPresence += XmppClient_OnPresence;

            this.sensorClient = new SensorClient(this.xmppClient);
        }
Beispiel #13
0
        public override SensorDataSubscriptionRequest SubscribeSensorDataMomentaryReadout(FieldSubscriptionRule[] Rules)
        {
            XmppAccountNode XmppAccountNode = this.XmppAccountNode;
            SensorClient    SensorClient;

            if (XmppAccountNode != null && (SensorClient = XmppAccountNode.SensorClient) != null)
            {
                return(SensorClient.Subscribe(this.RosterItem.LastPresenceFullJid, FieldType.Momentary, Rules,
                                              new Duration(false, 0, 0, 0, 0, 0, 1), new Duration(false, 0, 0, 0, 0, 1, 0), false));
            }
            else
            {
                return(null);
            }
        }
        public override void DisposeClients()
        {
            if (this.sensorServer != null)
            {
                this.sensorServer.Dispose();
                this.sensorServer = null;
            }

            if (this.sensorClient != null)
            {
                this.sensorClient.Dispose();
                this.sensorClient = null;
            }

            base.DisposeClients();
        }
Beispiel #15
0
        private ISensorClientService <TKey> GetClient(SensorClient client)
        {
            switch (client)
            {
            case SensorClient.Supla:
                return(suplaClientService);

            case SensorClient.Blebox:
                return(bleboxSensorClientService);

            default:
                break;
            }

            throw new NotImplementedException();
        }
Beispiel #16
0
        public override SensorDataClientRequest StartSensorDataMomentaryReadout()
        {
            XmppConcentrator Concentrator    = this.Concentrator;
            XmppAccountNode  XmppAccountNode = Concentrator.XmppAccountNode;
            SensorClient     SensorClient;

            if (XmppAccountNode != null && (SensorClient = XmppAccountNode.SensorClient) != null)
            {
                return(SensorClient.RequestReadout(Concentrator.RosterItem.LastPresenceFullJid,
                                                   new ThingReference[] { new ThingReference(this.nodeInfo.NodeId, this.nodeInfo.SourceId, this.nodeInfo.ParentId) }, FieldType.Momentary));
            }
            else
            {
                return(null);
            }
        }
Beispiel #17
0
        public override SensorDataClientRequest StartSensorDataFullReadout()
        {
            XmppConcentrator Concentrator    = this.Concentrator;
            XmppAccountNode  XmppAccountNode = Concentrator.XmppAccountNode;
            SensorClient     SensorClient;

            if (XmppAccountNode != null && (SensorClient = XmppAccountNode.SensorClient) != null)
            {
                return(SensorClient.RequestReadout(Concentrator.RosterItem.LastPresenceFullJid,
                                                   new ThingReference[] { new ThingReference(this.nodeInfo.NodeId, this.nodeInfo.SourceId, this.nodeInfo.Partition) }, FieldType.All));
            }
            else
            {
                throw new NotSupportedException();
            }
        }
Beispiel #18
0
        public override SensorDataSubscriptionRequest SubscribeSensorDataMomentaryReadout(FieldSubscriptionRule[] Rules)
        {
            XmppConcentrator Concentrator    = this.Concentrator;
            XmppAccountNode  XmppAccountNode = Concentrator.XmppAccountNode;
            SensorClient     SensorClient;

            if (XmppAccountNode != null && (SensorClient = XmppAccountNode.SensorClient) != null)
            {
                return(SensorClient.Subscribe(Concentrator.RosterItem.LastPresenceFullJid,
                                              new ThingReference[] { new ThingReference(this.nodeInfo.NodeId, this.nodeInfo.SourceId, this.nodeInfo.Partition) },
                                              FieldType.Momentary, Rules, new Duration(false, 0, 0, 0, 0, 0, 1), new Duration(false, 0, 0, 0, 0, 1, 0), false));
            }
            else
            {
                return(null);
            }
        }
Beispiel #19
0
        public override SensorDataSubscriptionRequest SubscribeSensorDataMomentaryReadout(FieldSubscriptionRule[] Rules)
        {
            if (this.isSensor)
            {
                XmppAccountNode XmppAccountNode = this.XmppAccountNode;
                SensorClient    SensorClient;

                if (XmppAccountNode != null && (SensorClient = XmppAccountNode.SensorClient) != null)
                {
                    return(SensorClient.Subscribe(this.RosterItem.LastPresenceFullJid, FieldType.Momentary, Rules,
                                                  Duration.FromSeconds(1), Duration.FromMinutes(1), false));
                }
                else
                {
                    return(null);
                }
            }
            else
            {
                throw new NotSupportedException();
            }
        }
Beispiel #20
0
		/// <summary>
		/// Invoked when application execution is being suspended.  Application state is saved
		/// without knowing whether the application will be terminated or resumed with the contents
		/// of memory still intact.
		/// </summary>
		/// <param name="sender">The source of the suspend request.</param>
		/// <param name="e">Details about the suspend request.</param>
		private void OnSuspending(object sender, SuspendingEventArgs e)
		{
			var deferral = e.SuspendingOperation.GetDeferral();

			this.subscription?.Unsubscribe();
			this.subscription = null;

			this.registryClient?.Dispose();
			this.registryClient = null;

			this.chatServer?.Dispose();
			this.chatServer = null;

			this.bobClient?.Dispose();
			this.bobClient = null;

			this.sensorServer?.Dispose();
			this.sensorServer = null;

			this.sensorClient?.Dispose();
			this.sensorClient = null;

			this.controlClient?.Dispose();
			this.controlClient = null;

			this.xmppClient?.Dispose();
			this.xmppClient = null;

			this.secondTimer?.Dispose();
			this.secondTimer = null;

			db?.Stop()?.Wait();
			db?.Flush()?.Wait();

			Log.Terminate();

			deferral.Complete();
		}
Beispiel #21
0
 public void InitailiseBSF(string user, string pwd)
 {
     m_sensorClient = new SensorClient("jl2", user, pwd);
     m_sensorClient.SensorClientCreateEvent += new SensorClientCreateEventHandler(OnSensorClientCreateEvent);
 }
 /// <summary>
 /// Manages a sensor data client request.
 /// </summary>
 /// <param name="Id">Request identity.</param>
 /// <param name="SensorClient">Sensor client object.</param>
 /// <param name="RemoteJID">JID of the other side of the conversation in the sensor data readout.</param>
 /// <param name="Actor">Actor causing the request to be made.</param>
 /// <param name="Nodes">Array of nodes to read. Can be null or empty, if reading a sensor that is not a concentrator.</param>
 /// <param name="Types">Field Types to read.</param>
 /// <param name="FieldNames">Names of fields to read.</param>
 /// <param name="From">From what time readout is to be made. Use <see cref="DateTime.MinValue"/> to specify no lower limit.</param>
 /// <param name="To">To what time readout is to be made. Use <see cref="DateTime.MaxValue"/> to specify no upper limit.</param>
 /// <param name="When">When the readout is to be made. Use <see cref="DateTime.MinValue"/> to start the readout immediately.</param>
 /// <param name="ServiceToken">Optional service token.</param>
 /// <param name="DeviceToken">Optional device token.</param>
 /// <param name="UserToken">Optional user token.</param>
 internal SensorDataClientRequest(string Id, SensorClient SensorClient, string RemoteJID, string Actor, IThingReference[] Nodes, FieldType Types,
                                  string[] FieldNames, DateTime From, DateTime To, DateTime When, string ServiceToken, string DeviceToken, string UserToken)
     : base(Id, RemoteJID, Actor, Nodes, Types, FieldNames, From, To, When, ServiceToken, DeviceToken, UserToken)
 {
     this.sensorClient = SensorClient;
 }
Beispiel #23
0
 /// <summary>
 /// Parses a personal event from its XML representation
 /// </summary>
 /// <param name="E">XML representation of personal event.</param>
 /// <returns>Personal event object.</returns>
 public override IPersonalEvent Parse(XmlElement E)
 {
     return(SensorClient.ParseFields(E));
 }
Beispiel #24
0
        /// <summary>
        /// Executes a node.
        /// </summary>
        /// <param name="Variables">Set of variables for the activity.</param>
        /// <returns>Next node of execution, if different from the default, otherwise null (for default).</returns>
        public override async Task <LinkedListNode <IActivityNode> > Execute(Variables Variables)
        {
            string To = this.to.GetValue(Variables);

            if (!(this.GetActorObject(this.actor, Variables) is SensorClient SensorClient))
            {
                throw new Exception("Actor not an XMPP Sensor Client.");
            }

            if (XmppClient.BareJidRegEx.IsMatch(To))
            {
                RosterItem Item = SensorClient.Client[To];
                if (Item is null)
                {
                    throw new Exception("No connection in roster with Bare JID: " + To);
                }

                if (!Item.HasLastPresence || !Item.LastPresence.IsOnline)
                {
                    throw new Exception("Contact not online: " + To);
                }

                To = Item.LastPresenceFullJid;
            }

            TaskCompletionSource <bool> T = new TaskCompletionSource <bool>();
            Dictionary <string, Field>  FieldsAsObject = this.responseType == SensorDataResponseType.Object ? new Dictionary <string, Field>() : null;
            List <Field>            FieldsAsArray      = this.responseType == SensorDataResponseType.Array ? new List <Field>() : null;
            List <ThingError>       Errors             = new List <ThingError>();
            SensorDataClientRequest Request            = SensorClient.RequestReadout(To, this.nodeReferences, this.fields, this.fieldTypes);

            Request.OnErrorsReceived += (Sender, NewErrors) =>
            {
                lock (Errors)
                {
                    Errors.AddRange(NewErrors);
                }

                return(Task.CompletedTask);
            };

            Request.OnFieldsReceived += (Sender, NewFields) =>
            {
                if (this.responseType == SensorDataResponseType.Object)
                {
                    lock (FieldsAsObject)
                    {
                        foreach (Field F in NewFields)
                        {
                            FieldsAsObject[F.Name] = F;
                        }
                    }
                }
                else
                {
                    lock (FieldsAsArray)
                    {
                        FieldsAsArray.AddRange(NewFields);
                    }
                }

                return(Task.CompletedTask);
            };

            Request.OnStateChanged += (Sender, NewState) =>
            {
                switch (NewState)
                {
                case SensorDataReadoutState.Done:
                    T.TrySetResult(true);
                    break;

                case SensorDataReadoutState.Failure:
                case SensorDataReadoutState.Cancelled:
                    T.TrySetResult(false);
                    break;
                }

                return(Task.CompletedTask);
            };

            if (!await T.Task)
            {
                StringBuilder sb = new StringBuilder();

                sb.AppendLine("Sensor Data readout failed. Errors reported: ");
                sb.AppendLine();

                foreach (ThingError Error in Errors)
                {
                    sb.AppendLine(Error.ErrorMessage);                      // TODO: Node reference, if available.
                }
                throw new Exception(sb.ToString());
            }

            Variables[this.responseVariable] = (object)FieldsAsObject ?? FieldsAsArray.ToArray();

            return(null);
        }
Beispiel #25
0
		private void AttachFeatures()
		{
			this.sensorServer = new SensorServer(this.xmppClient, true);
			this.sensorServer.OnExecuteReadoutRequest += (sender, e) =>
			{
				try
				{
					Log.Informational("Performing readout.", this.xmppClient.BareJID, e.Actor);

					List<Field> Fields = new List<Field>();
					DateTime Now = DateTime.Now;

					if (e.IsIncluded(FieldType.Identity))
					{
						Fields.Add(new StringField(ThingReference.Empty, Now, "Device ID", this.deviceId, FieldType.Identity, FieldQoS.AutomaticReadout));

						if (!string.IsNullOrEmpty(this.sensorJid))
						{
							Fields.Add(new StringField(ThingReference.Empty, Now, "Sensor, JID", this.sensorJid, FieldType.Identity, FieldQoS.AutomaticReadout));

							if (this.sensor != null)
							{
								if (!string.IsNullOrEmpty(this.sensor.NodeId))
									Fields.Add(new StringField(ThingReference.Empty, Now, "Sensor, Node ID", this.sensor.NodeId, FieldType.Identity, FieldQoS.AutomaticReadout));

								if (!string.IsNullOrEmpty(this.sensor.SourceId))
									Fields.Add(new StringField(ThingReference.Empty, Now, "Sensor, Source ID", this.sensor.SourceId, FieldType.Identity, FieldQoS.AutomaticReadout));

								if (!string.IsNullOrEmpty(this.sensor.Partition))
									Fields.Add(new StringField(ThingReference.Empty, Now, "Sensor, Partition", this.sensor.Partition, FieldType.Identity, FieldQoS.AutomaticReadout));
							}
						}

						if (!string.IsNullOrEmpty(this.actuatorJid))
						{
							Fields.Add(new StringField(ThingReference.Empty, Now, "Actuator, JID", this.actuatorJid, FieldType.Identity, FieldQoS.AutomaticReadout));

							if (this.actuator != null)
							{
								if (!string.IsNullOrEmpty(this.actuator.NodeId))
									Fields.Add(new StringField(ThingReference.Empty, Now, "Actuator, Node ID", this.actuator.NodeId, FieldType.Identity, FieldQoS.AutomaticReadout));

								if (!string.IsNullOrEmpty(this.actuator.SourceId))
									Fields.Add(new StringField(ThingReference.Empty, Now, "Actuator, Source ID", this.actuator.SourceId, FieldType.Identity, FieldQoS.AutomaticReadout));

								if (!string.IsNullOrEmpty(this.actuator.Partition))
									Fields.Add(new StringField(ThingReference.Empty, Now, "Actuator, Partition", this.actuator.Partition, FieldType.Identity, FieldQoS.AutomaticReadout));
							}
						}
					}

					if (e.IsIncluded(FieldType.Status))
					{
						RosterItem Item;

						if (string.IsNullOrEmpty(this.sensorJid))
							Fields.Add(new StringField(ThingReference.Empty, Now, "Sensor, Availability", "Not Found", FieldType.Status, FieldQoS.AutomaticReadout));
						else
						{
							Item = this.xmppClient[this.sensorJid];
							if (Item is null)
								Fields.Add(new StringField(ThingReference.Empty, Now, "Sensor, Availability", "Not Found", FieldType.Status, FieldQoS.AutomaticReadout));
							else if (!Item.HasLastPresence)
								Fields.Add(new StringField(ThingReference.Empty, Now, "Sensor, Availability", "Offline", FieldType.Status, FieldQoS.AutomaticReadout));
							else
								Fields.Add(new StringField(ThingReference.Empty, Now, "Sensor, Availability", Item.LastPresence.Availability.ToString(), FieldType.Status, FieldQoS.AutomaticReadout));
						}

						if (string.IsNullOrEmpty(this.actuatorJid))
							Fields.Add(new StringField(ThingReference.Empty, Now, "Actuator, Availability", "Not Found", FieldType.Status, FieldQoS.AutomaticReadout));
						else
						{
							Item = this.xmppClient[this.actuatorJid];
							if (Item is null)
								Fields.Add(new StringField(ThingReference.Empty, Now, "Actuator, Availability", "Not Found", FieldType.Status, FieldQoS.AutomaticReadout));
							else if (!Item.HasLastPresence)
								Fields.Add(new StringField(ThingReference.Empty, Now, "Actuator, Availability", "Offline", FieldType.Status, FieldQoS.AutomaticReadout));
							else
								Fields.Add(new StringField(ThingReference.Empty, Now, "Actuator, Availability", Item.LastPresence.Availability.ToString(), FieldType.Status, FieldQoS.AutomaticReadout));
						}
					}

					if (e.IsIncluded(FieldType.Momentary))
					{
						if (this.light.HasValue)
							Fields.Add(new QuantityField(ThingReference.Empty, Now, "Light", this.light.Value, 2, "%", FieldType.Momentary, FieldQoS.AutomaticReadout));

						if (this.motion.HasValue)
							Fields.Add(new BooleanField(ThingReference.Empty, Now, "Motion", this.motion.Value, FieldType.Momentary, FieldQoS.AutomaticReadout));

						if (this.output.HasValue)
							Fields.Add(new BooleanField(ThingReference.Empty, Now, "Output", this.output.Value, FieldType.Momentary, FieldQoS.AutomaticReadout));
					}

					e.ReportFields(true, Fields);
				}
				catch (Exception ex)
				{
					e.ReportErrors(true, new ThingError(ThingReference.Empty, ex.Message));
				}

				return Task.CompletedTask;
			};

			this.xmppClient.OnError += (Sender, ex) =>
			{
				Log.Error(ex);
				return Task.CompletedTask;
			};

			this.xmppClient.OnPasswordChanged += (Sender, e) =>
			{
				Log.Informational("Password changed.", this.xmppClient.BareJID);
			};

			this.xmppClient.OnPresenceSubscribe += (Sender, e) =>
			{
				Log.Informational("Accepting friendship request.", this.xmppClient.BareJID, e.From);
				e.Accept();
				return Task.CompletedTask;
			};

			this.xmppClient.OnPresenceUnsubscribe += (Sender, e) =>
			{
				Log.Informational("Friendship removed.", this.xmppClient.BareJID, e.From);
				e.Accept();
				return Task.CompletedTask;
			};

			this.xmppClient.OnPresenceSubscribed += (Sender, e) =>
			{
				Log.Informational("Friendship request accepted.", this.xmppClient.BareJID, e.From);

				if (string.Compare(e.FromBareJID, this.sensorJid, true) == 0)
					this.SubscribeToSensorData();

				return Task.CompletedTask;
			};

			this.xmppClient.OnPresenceUnsubscribed += (Sender, e) =>
			{
				Log.Informational("Friendship removal accepted.", this.xmppClient.BareJID, e.From);
				return Task.CompletedTask;
			};

			this.xmppClient.OnPresence += XmppClient_OnPresence;

			this.bobClient = new BobClient(this.xmppClient, Path.Combine(Path.GetTempPath(), "BitsOfBinary"));
			this.chatServer = new ChatServer(this.xmppClient, this.bobClient, this.sensorServer);

			// XEP-0054: vcard-temp: http://xmpp.org/extensions/xep-0054.html
			this.xmppClient.RegisterIqGetHandler("vCard", "vcard-temp", this.QueryVCardHandler, true);

			this.sensorClient = new SensorClient(this.xmppClient);
			this.controlClient = new ControlClient(this.xmppClient);
		}