ipcconnectedfactoryexchange / cfx Goto Github PK
View Code? Open in Web Editor NEWLicense: Apache License 2.0
License: Apache License 2.0
I am an applications engineer not a developer so please bear with me.
On our test equipment we currently are able to create custom routines that, after successful validation of a UUT serial number, can download from the customer's MES system unique items like a MAC address or firmware to be programmed into the UUT at test. The validation and download of anything unique is completely custom, based on the customer's MES implementation and their needs.
So I'm wondering when a customer moves to an IPC-CFX implementation, does CFX allow for transmission of this kind of data, either as part of a successful validation or as a separate action taken after a successful validation. As I imagine that CFX would be the sole messaging mechanism with the MES system, I do not envision using a custom app outside of CFX doing this.
I just wonder if the standard allows for this somehow.
Hi,
May I know if there are any plugins for CFX in python as in C# and also sample codes on establishing the connection to the broker?
The documents in this link are all only for C#.
http://www.connectedfactoryexchange.com/CFXDemo/sdk/html/cfb57aac-b696-4c6c-b94b-f034b37daf26.htm
So I had been wondering if there are any plugins that I can use for python.
Thank you .
Regards,
Snow Bunny.
Hi,
I need help consuming large messages using CFX library.
Using the CFX Channel subscription to get messages, I got an exception in my CFX software:
I/O: Amqp.AmqpException: Invalid frame size:993259, maximum frame size:262144.
The message was not consumed.
It seems the amqp.Net library, CFX is using, has a default message size value: DefaultMaxFrameSize = 256 * 1024
And a message I tried to consume is 993259 bytes large;
I tried to set AmqpCFXEndpoint.MaxFrameSize = 1048576;
But it has no effect on the MaxFrameSize of Amqp.Net;
It seems setting AmqpCFXEndpoint.MaxFrameSize has no effect whatsoever;
It seems also this limit apply to receive buffer size only;
Is there a standard in CFX to break down a message in several pieces ?
Here is where the exception is thrown:
// amqpnetlite\src\Net\AsyncPump.cs
` public async Task PumpAsync(uint maxFrameSize, Func<ProtocolHeader, bool> onHeader, Func<ByteBuffer, bool> onBuffer)
await this.ReceiveBufferAsync(header, 0, FixedWidth.UInt).ConfigureAwait(false);
int frameSize = AmqpBitConverter.ReadInt(header, 0);
if ((uint)frameSize > maxFrameSize)
{
throw new AmqpException(ErrorCode.InvalidField,
Fx.Format(SRAmqp.InvalidFrameSize, frameSize, maxFrameSize));
}
ByteBuffer buffer = this.bufferManager.GetByteBuffer(frameSize);
`
And here is how I found a way to increase the maximum frame size in order to read the big message:
What do you think of it ?
`// The code in my software:
theEndpoint = new AmqpCFXEndpoint();
theEndpoint.Open(cfxHandle);
AmqpCFXEndpoint.MaxFrameSize = 1048576;
// CFX\Transport\AmqpConnection.cs
public void OpenConnection()
{
Cleanup();
Exception connectException = null;
try
{
Open o = new Open()
{
ContainerId = Endpoint.CFXHandle != null ? Endpoint.CFXHandle : Guid.NewGuid().ToString(),
HostName = VirtualHostName
};
ConnectionFactory factory = new ConnectionFactory();
if (this.NetworkUri.Scheme.ToUpper() == "AMQPS") factory.SSL.RemoteCertificateValidationCallback = ValidateServerCertificate;
if (string.IsNullOrWhiteSpace(this.NetworkUri.UserInfo)) factory.SASL.Profile = SaslProfile.Anonymous;
// Assigning CFX MaxFrameSize to AMQP MaxFrameSize and thus enabling reception of messages larger than Amqp default: 256 * 1024 bytes
factory.AMQP.MaxFrameSize = Convert.ToInt32(AmqpCFXEndpoint.MaxFrameSize);
Task<Connection> t = factory.CreateAsync(new Address(NetworkUri.ToString()), o, null);
t.Wait(5000);
if (t.Status != TaskStatus.RanToCompletion)
{
throw new Exception("Timeout on CreateAsync");
}
connection = t.Result;
connection.Closed += AmqpObject_Closed;
session = new Session(connection);
session.Closed += AmqpObject_Closed;
}
catch (Exception ex)
{
connectException = ex;
Debug.WriteLine(ex.Message);
Cleanup();
}
if (connectException != null)
{
Cleanup();
throw connectException;
}
}
`
Hi,
More machine fault information need to be added. We have a list as attached file. Could you please review them and implement them in the new version?
Hi everybody,
The CFX SDK allows to configurate the timeout for a request (default value is 30 seconds). When I set it to, for example 3 seconds, it works when the PC that I try to reach is ON (with the software which is supposed to answer to the request not launched). It only waits for 3 seconds in this case, as wanted.
But if the PC is OFF, the configurated timeout is not working and I have to wait for about 40 seconds to go out of the ExecuteRequest() function.
Has anyone encountered the same issue? I'm afraid it's probably an AMQP issue but we have experts here and I hope there is a solution! ;)
Thanks!
Alexis
I've been fighting with this issue for a little while now so hopefully, somebody here can help me.
I've tried following the tutorial available on the connectedfactory but I must be doing something wrong.
Here is what I have:
Send:
`
private void send(object sender, RoutedEventArgs e)
{
AmqpCFXEndpoint endpoint = new AmqpCFXEndpoint();
endpoint.Open("Vendor1.Model1.Machine34");
// Encode your username and password into the destination Uri
string username = "newadmin";
string password = "s0m3p4ssw0rd";
string hostname = "192.168.1.52";
// eg. amqps://myusername:[email protected]
Uri uri = new Uri(string.Format("amqps://{0}:{1}@{2}", username, password, hostname));
// Target exchange on broker (shown here in RabbitMQ compatible format)
string amqpTarget = "/exchange/CFXExchange";
endpoint.AddPublishChannel(uri, amqpTarget);
string targetEndpointHostname = "192.168.1.52";
string targetCFXHandle = "Vendor2.Model2.Machine55";
string remoteUri = string.Format("amqp://{0}", targetEndpointHostname);
// Set a timeout of 20 seconds. If the target endpoint does not
// respond in this time, the request will time out.
AmqpCFXEndpoint.RequestTimeout = TimeSpan.FromSeconds(20);
// Build a GetEndpointInfomation Request
CFXEnvelope request = CFXEnvelope.FromCFXMessage(new WhoIsThereRequest()
{
});
request.Target = amqpTarget;
CFXEnvelope response = endpoint.ExecuteRequest(remoteUri, request);
}
`
Receive:
`
private void open(object sender, RoutedEventArgs e)
{
AmqpCFXEndpoint endpoint = new AmqpCFXEndpoint();
endpoint.Open("Vendor2.Model2.Machine55");
// Encode your username and password into the destination Uri
string username = "newadmin";
string password = "s0m3p4ssw0rd";
string hostname = "192.168.1.52";
// eg. amqps://myusername:[email protected]
Uri uri = new Uri(string.Format("amqps://{0}:{1}@{2}", username, password, hostname));
// Source queue on broker (shown here in RabbitMQ compatible format)
string amqpSource = "/queue/CFXQueque";
endpoint.OnRequestReceived += Endpoint_OnRequestReceived;
endpoint.AddSubscribeChannel(uri, amqpSource);
}
private CFXEnvelope Endpoint_OnRequestReceived(CFXEnvelope request)
{
// Encode your username and password into the destination Uri
string username = "newadmin";
string password = "s0m3p4ssw0rd";
string hostname = "192.168.1.52";
// eg. amqps://myusername:[email protected]
Uri myRequestUri = new Uri(string.Format("amqps://{0}:{1}@{2}", username, password, hostname));
string myCFXHandle = "Vendor2.Model2.Machine55";
// Process request. Return Result.
if (request.MessageBody is WhoIsThereRequest)
{
CFXEnvelope result = CFXEnvelope.FromCFXMessage(new WhoIsThereResponse()
{ CFXHandle = myCFXHandle, RequestNetworkUri = myRequestUri.ToString(), RequestTargetAddress = "" });
result.Source = myCFXHandle;
result.Target = request.Source;
return result;
}
return null;
}
`
I see the messages are received by the AMQP ( see img )
Any help would be appreciated
Hello together
At first sorry for my expandable english...
For my understanding:
I will etablish CFX between a MES (in the first step as simulator) and a machine throw RabbitMQ. I have a running RabbitMQ server instance . I have created an exchange called "CFXExchange". I have created a queue called "werkbuch". I have bounded the queue "werkbuch" to the "CFXExchange".
The CFXExchange is configured as "Fanout". This works like a broadcasting message. If I send a message to this Exchange it will post the message to all queues which are binded.
Are all Endpoints in CFX a Queue in RabbitMQ?
Sends the Endpoint like a machine a broadcast message to an Exchange?
Sends the Endpoint like a MES a message directly to a Queue?
Whats the missing link between CFXHandle an ??? in RabbitMQ?
I was going through the tutorial in RabbitMQ and now I understand (basics) the communication in RabbitMQ. But how I have to do to start the implementation of CFX in my plant?
Can everyone help me to build a big picture in my head?
There are two parameters RequestNetworkUri and RequestTargetAddress to be defined when creating a CFX endpoint. As I know, they are neither event channel nor subscription channel, so what's the purpose of them?
Hello,
When calling ExecuteRequest
, the following JSON parse exception is thrown:
ERROR MESSAGE: Unexpected character encountered while parsing value: �. Path '', line 0, position 0.
at CFX.Transport.AmqpCFXEndpoint.d__138.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at CFX.Transport.AmqpCFXEndpoint.ExecuteRequest(String targetUri, CFXEnvelope request)
at CGC.HellerRecipeExtractor.Service.CFXController.Connect() in.....
I'm running RabbitMQ 3.8.12 locally with amqp1.0 plugin enabled. I'm trying to retrieve the recipe running on a Heller oven. The Heller CFX app and my .NET app are all running locally. I created a new exchange called "Heller".
Below is the code to create the envelope and call ExecuteRequest - taken from the Demo app on GitHub.
CFXEnvelope env = new CFXEnvelope()
{
Source = MyEndpoint.CFXHandle,
Target = hellerHandle,
MessageBody = new AreYouThereRequest()
{
CFXHandle = myHandle
}
};
env.Source = myHandle;
env.Target = hellerHandle;
CFXEnvelope response = null;
try
{
response = MyEndpoint.ExecuteRequest(hellerUri, env);
}
catch (Exception x)
{
logger.Error($"ERROR OCCURRED MAKING REQUEST TO {hellerUri}, handle {hellerHandle}.\nERROR MESSAGE: {x.Message} \n{x.StackTrace}");
}
Here's the CFX log:
Info: 2021-03-02T09:38:27.6207836+00:00 Connecting to amqp://localhost:5672/
SEND AMQP 3 1 0 0
SEND AMQP 3 1 0 0
SEND AMQP 3 1 0 0
Info: 2021-03-02T09:38:27.6478469+00:00 Connected to amqp://localhost:5672/. Establishing Links...
RECV sasl-mechanisms(sasl-server-mechanisms:[ANONYMOUS,AMQPLAIN,PLAIN])
RECV AMQP 0 1 0 0
RECV AMQP 0 1 0 0
SEND AMQP 0 1.0.0
SEND (ch=0) begin(remote-channel:0,next-outgoing-id:4294967293,incoming-window:2048,outgoing-window:2048,handle-max:63)
RECV (ch=0) attach(name:/exchange/Heller,handle:0,role:True,snd-settle-mode:Unsettled,rcv-settle-mode:First,source:source(durable:0,timeout:0,dynamic:False),target:target(address:/exchange/Heller,durable:0,timeout:0,dynamic:False),incomplete-unsettled:False,initial-delivery-count:0,max-message-size:0)
SEND (ch=0) attach(name:/exchange/Heller,handle:0,role:False,snd-settle-mode:Unsettled,rcv-settle-mode:First,source:source(durable:0,timeout:0,dynamic:False),target:target(address:/exchange/Heller,durable:0,timeout:0,dynamic:False),incomplete-unsettled:False,initial-delivery-count:0,max-message-size:0)
RECV (ch=0) begin(remote-channel:0,next-outgoing-id:0,incoming-window:65535,outgoing-window:65535,handle-max:63)
RECV (ch=0) flow(next-in-id:4294967293,in-window:65535,next-out-id:0,out-window:65535,handle:0,delivery-count:0,link-credit:65536,available:0,drain:False,echo:False)
RECV sasl-outcome(code:Ok)
Debug: 2021-03-02T09:38:27.6548654+00:00 sender-/exchange/Heller Enqueuing 1 messages.
RECV (ch=0) open(container-id:rabbit@MyWorkStation,max-frame-size:250000,channel-max:0,idle-time-out:60000,properties:[cluster_name:rabbit@MyWorkStation,copyright:Copyright (c) 2007-2021 VMware, Inc. or its affiliates.,information:Licensed under the MPL 2.0. Website: https://rabbitmq.com,platform:Erlang/OTP 23.2.6,product:RabbitMQ,version:3.8.12])
Debug: 2021-03-02T09:38:27.7792208+00:00 sender-/exchange/Heller Triggering Processing...
Debug: 2021-03-02T09:38:31.9063537+00:00 sender-/exchange/Heller Attempting to process queued messages...
Debug: 2021-03-02T09:38:33.7618217+00:00 GZIP Compressed Message(s) of Size 346 bytes to 250 bytes
Debug: 2021-03-02T09:38:33.7628243+00:00 GZIP Compressed Message(s) of Size 395 bytes to 283 bytes
SEND AMQP 3 1 0 0
RECV sasl-mechanisms(sasl-server-mechanisms:[ANONYMOUS])
SEND sasl-init(mechanism:ANONYMOUS,initial-response:...)
RECV sasl-outcome(code:Ok)
RECV AMQP 0 1 0 0
RECV (ch=0) begin(remote-channel:0,next-outgoing-id:0,incoming-window:2048,outgoing-window:2048,handle-max:63)
RECV (ch=0) open(container-id:ContainerHost-4f7aacdec80a4807bca6d630e283aad4,host-name:10.162.14.104,max-frame-size:262144,channel-max:255,idle-time-out:2147483647)
SEND (ch=0) attach(name:request-receiver,handle:0,role:True,snd-settle-mode:Unsettled,rcv-settle-mode:First,source:source(address:Heller.Reflow.1707-Line,durable:0,timeout:0,dynamic:False),target:target(address:CGControls.Heller.RecipeExtractor,durable:0,timeout:0,dynamic:False),incomplete-unsettled:False,initial-delivery-count:0,max-message-size:0)
SEND (ch=0) begin(remote-channel:0,next-outgoing-id:4294967293,incoming-window:2048,outgoing-window:2048,handle-max:63)
SEND (ch=0) flow(next-in-id:0,in-window:2048,next-out-id:4294967293,out-window:2048,handle:0,delivery-count:0,link-credit:300,available:0,drain:False,echo:False)
SEND AMQP 0 1.0.0
SEND (ch=0) attach(name:CGControls.Heller.RecipeExtractor,handle:1,role:False,snd-settle-mode:Unsettled,rcv-settle-mode:First,source:source(durable:0,timeout:0,dynamic:False),target:target(address:Heller.Reflow.1707-Line,durable:0,timeout:0,dynamic:False),incomplete-unsettled:False,initial-delivery-count:0,max-message-size:0)
SEND (ch=0) open(container-id:AMQPNetLite-201dc026,host-name:10.162.14.104,max-frame-size:262144,channel-max:255,idle-time-out:2147483647)
RECV (ch=0) attach(name:request-receiver,handle:0,role:False,snd-settle-mode:Unsettled,rcv-settle-mode:First,source:source(address:Heller.Reflow.1707-Line,durable:0,timeout:0,dynamic:False),target:target(address:CGControls.Heller.RecipeExtractor,durable:0,timeout:0,dynamic:False),incomplete-unsettled:False,initial-delivery-count:0,max-message-size:0)
RECV (ch=0) attach(name:request-receiver,handle:0,role:False,snd-settle-mode:Unsettled,rcv-settle-mode:First,source:source(address:Heller.Reflow.1707-Line,durable:0,timeout:0,dynamic:False),target:target(address:CGControls.Heller.RecipeExtractor,durable:0,timeout:0,dynamic:False),incomplete-unsettled:False,initial-delivery-count:0,max-message-size:0)
RECV (ch=0) attach(name:CGControls.Heller.RecipeExtractor,handle:1,role:True,snd-settle-mode:Unsettled,rcv-settle-mode:First,source:source(durable:0,timeout:0,dynamic:False),target:target(address:Heller.Reflow.1707-Line,durable:0,timeout:0,dynamic:False),incomplete-unsettled:False,initial-delivery-count:0,max-message-size:0)
SEND (ch=0) transfer(handle:0,delivery-id:0,delivery-tag:00000001,message-format:0,settled:False,more:False,rcv-settle-mode:First,resume:False,aborted:False,batchable:False) payload 554
SEND (ch=0) transfer(handle:1,delivery-id:0,delivery-tag:00000001,message-format:0,settled:False,more:False,rcv-settle-mode:First,resume:False,aborted:False,batchable:False) payload 553
RECV (ch=0) disposition(role:True,first:0,last:0,settled:True,state:accepted(),batchable:False)
Debug: 2021-03-02T09:38:33.8395512+00:00 sender-/exchange/Heller 1 messages transmitted. 0 messages remaining in spool.
RECV (ch=0) disposition(role:True,first:0,last:0,settled:True,state:accepted(),batchable:False)
RECV (ch=0) close(error:error(condition:amqp:internal-error,description:Unexpected character encountered while parsing value: �. Path '', line 0, position 0.))
SEND (ch=0) close()
Error: 2021-03-02T09:38:33.8505540+00:00 Unexpected character encountered while parsing value: �. Path '', line 0, position 0.
Error: 2021-03-02T09:38:33.8575720+00:00 at Amqp.ReceiverLink.ReceiveInternal(MessageCallback callback, Int32 timeout) in C:\Users\mqt\repo\amqpnetlite.rel\src\ReceiverLink.cs:line 472
at Amqp.ReceiverLink.Receive(TimeSpan timeout) in C:\Users\mqt\repo\amqpnetlite.rel\src\ReceiverLink.cs:line 235
at CFX.Transport.AmqpCFXEndpoint.d__138.MoveNext()
SEND (ch=0) detach(handle:0,closed:True)
RECV (ch=0) detach(handle:0,closed:False)
I want to use GetMaterialInformationRequest and GetMaterialInformationResponse Messages but these are not yet packaged in nuget. Does CFX repo has any timeline for publishing nuget package?
I have a three part question about responses.
I assume if an MES system wanted to perform a WhoIsThereRequest, it would publish to a channel that all the machine endpoints are subscribed to. Is this correct? If so, would the machines just publish a response to a channel that the MES system subscribes to? Or is there a different way to respond to that query.
It appears ExecuteRequest is a direct link to an ad-hoc "amqp server" resident within the SDK (assuming a requestUri and a listener is added). So endpoint A initiates a direct ExectureRequest directly to endpoint B and the OnRequestReceived event is fired on endpoint B. How does endpoint B respond to the request? Does it just respond with it's own ExecuteRequest.
Finally, what is the difference between these two events: OnRequestReceived versus OnCFXMessageReceivedFromListener.
When sending a CFX message the AmqpConnection class calls the OpenConnection which is a synchrounous call. This itself is calling the Communication library, which is a asynchrounous call.
See code
Task t = factory.CreateAsync(new Address(NetworkUri.ToString()), o, null);
t.Wait(5000);
if (t.Status != TaskStatus.RanToCompletion)
{
throw new Exception("Timeout on CreateAsync");
}
This will lead to blocking calls when publishing messages whilce the broker is not reachable with an timeout of 5 seconds.
Hi,
I am new to CFX standard and still trying to get a handle on the basics. I read through the CFX Demo and installed the SDK through NuGet Package available on Github. If I understand correctly the CFX SDK (a .Net library) is available that can be called in other software platforms. I am primarily a LabVIEW developer and want to implement CFX messaging through LabVIEW.
So far I have been trying to get the CFX Demo working from LabVIEW but I have not been able to connect to the host site. Maybe I am calling the wrong Properties/Methods. I was wondering if anyone here has used/called the SDK from LabVIEW and successful in getting the Demo to work. If yes, I would appreciate if you can share your LabVIEW code OR give suggestions to help me get through the issue.
Thanks,
Chetan
Hi,
May I know if CFX support LDAP authentication to broker?
I am using the following code to establish a connection to the rabbitmq broker.
this.BrokerUri = new Uri($"amqp://{username}:{Uri.EscapeDataString(password)}@{hostname}:{port}");
it works when I am using RabbitMQ Client C# with LDAP backend enabled for rabbitMQ, but when I tried the same for CFX to establish a connection to the RabbitMQ broker.
It will return successfull at "endpoint.TestChannel" but
It throws error me the following error at the "endpoint.TestPublishChannel" and it will not allow to publish messages.
Reader error: {badmatch,
{error,
{'EXIT',
{{badmatch,
{error,
{{{badmatch,{error,{auth_failure,"Refused"}}},
[{rabbit_amqp1_0_session_process,init,1,
[{file,"src/rabbit_amqp1_0_session_process.erl"},
{line,52}]},
{gen_server2,init_it,6,
[{file,"src/gen_server2.erl"},{line,554}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,249}]}]},
{child,undefined,channel,
{rabbit_amqp1_0_session_process,start_link,
[{0,<0.2281.0>,<0.2286.0>,
{user,<<"snow.bunny">>,
[administrator,management],
[{rabbit_auth_backend_ldap,
{impl,"[email protected]",
<<"t@stSnowPassword">>}}]},
<<"/">>,249992,
{amqp_adapter_info,
{0,0,0,0,0,0,0,1},
5672,
{0,0,0,0,0,0,0,1},
4150,<<"[::1]:4150 -> [::1]:5672">>,
{'AMQP',"1.0"},
[{ssl,false}]},
<0.2283.0>}]},
intrinsic,30000,worker,
[rabbit_amqp1_0_session_process]}}}},
[{rabbit_amqp1_0_session_sup,start_link,1,
[{file,"src/rabbit_amqp1_0_session_sup.erl"},{line,53}]},
{supervisor2,do_start_child_i,3,
[{file,"src/supervisor2.erl"},{line,391}]},
{supervisor2,handle_call,3,
[{file,"src/supervisor2.erl"},{line,417}]},
{gen_server,try_handle_call,4,
[{file,"gen_server.erl"},{line,661}]},
{gen_server,handle_msg,6,
[{file,"gen_server.erl"},{line,690}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,249}]}]}}}}
[{rabbit_amqp1_0_reader,send_to_new_1_0_session,3,
[{file,"src/rabbit_amqp1_0_reader.erl"},{line,690}]},
{rabbit_amqp1_0_reader,handle_1_0_session_frame,3,
[{file,"src/rabbit_amqp1_0_reader.erl"},{line,467}]},
{rabbit_amqp1_0_reader,handle_1_0_frame,4,
[{file,"src/rabbit_amqp1_0_reader.erl"},{line,321}]},
{rabbit_amqp1_0_reader,recvloop,2,
[{file,"src/rabbit_amqp1_0_reader.erl"},{line,123}]},
{rabbit_reader,run,1,[{file,"src/rabbit_reader.erl"},{line,459}]},
{rabbit_reader,start_connection,4,
[{file,"src/rabbit_reader.erl"},{line,358}]},
{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,249}]}]
I am not sure what I am missing here that is causing me to get the error.
Any advise / guides will be appreciated.
Thank you.
Regards,
Snow Bunny.
Is there an (unreleased) implementation of CFX for NodeJS / Javascript?
Especially for the AmqpCFXEndpoint class to provide request/response endpoints?
Thanks
In isnspection step customer wants to use AOI readed barcodes for de-panlization process for some products.
We need a way to send that trigger through CFX. Is there any suitable message for this purpose?
What parameter should we pass in public void AddListener(string targetAddress);?
Can anybody give me an example of target address
I am getting the following error: {"The Endpoint must have an a request processor set up via the Open method in order to receive messages on a listener."}
Hello,
I have seen that for example UnitsProcessed has a property "OverallResult", why PCBSelectiveSoldered does not have this property?
BR
Özgür
Hi,
I am new in CFX and RabbitMQ.
I had followed the tutorial on both the CFX and also the RabbitMQ to publish and consume messages.
My broker is setup as follows.
I had manually created my exchange, queue and bindings in RabbitMQ Broker =
exchangeA -> routingKeyA -> queueA (Durable queue , without any additional arguments parameters included)
CFX =
Uri uri = new Uri($"amqp://{Username}:{Password}@localhost:5672");
string exchangeAddress = $"/exchange/exhangeA/routingKeyA";
string queueAddress = $"/queue/queueA/";
endpoint.AddPublishChannel(uri,exchangeAddress);
endpoint.AddSubscribeChannel(uri,queueAddress);
Result:
However if I delete the queue and recreate it using the rabbitMQ management, and make it into a lazy queue by putting arguments with "x-queue-mode" = true, or enable auto-delete to true for the queue, my CFX is able to publish messages , but it is unable to consume messages from the queue.
An error message will keep showing that as follows:
"ERROR extablishing connection to queue = PRECONDITION_FAILED - inequivalent arg 'auto_delete' for queue 'queueA' in vhost '/': received 'false' but current is 'true'"
I had already set up the bindings for the queue and exchanges.
I would appreciate it if someone will kindly please guide me / let me know if there is a way to consume message from the queue , if the queue created in the RabbitMQ broker consist of arguments? Or currently CFX is unable to consume message from the queue if the queue was created with arguments, and it is only able to consume message from the queue which is durable without any arguments set?
Kindly please correct me if I am wrong.
Any feedback would be appreciated.
Thanking you in anticipation.
Regards,
Snow Bunny.
Hi,
I am considering storing CFX Data in a database; Has someone done it already ?
I am interested mostly in the TestAndInspection class.
If it is the case, can he share a create script for it ?
Thank you
Hi,
I am trying to use the SDK to subscribe to an endpoint using AddSubscribeChannel(). It works with a local implementation of RabbitMQ, but not with the CFX Demo.
I get the error message: ACCESS_REFUSED to queue 'AegisCloud' for user 'guest'.
I guess I don't have the access rights to subscribe.
Is there a queue available with access rights for guest ?
What can be done to obtain a user with access rights to be able to test receiving messages ?
Thank you
Daniel SIRAN
ASTER Technologies
Whether you can use golang implementation
Hi,
May I know if anyone knows how to make exclusive queues in the RabbitMQ broker when a connection is established using CFX library?
I would like the queue in the broker to be deleted automatically once the CFX connection is closed.
I know that it is possible if I am using RabbitMQ Client Library, but that also means that I have to establish a connection to the broker using the RabbitMQ client instead of the CFX library.
I would like to do the same but using CFX library. Is it possible?
I do not see any parameters in the CFX library which allows me to do that. May I know if exclusive queues are supported using CFX library?
Thanking you in anticipation.
I have already submitted a question about testing the online CFX Demo broker.
What should we do, at ASTER Technologies, to have a machine on the list ?
How can I test consuming messages from the online Aegis broker ?
No one answered. I addressed the message to Michael Ford, and got no answer.
At least tell me to whom should I address my request.
Chris, can you help ?
Thank you
When an AmqpCFXEndpoint connection has been opened and the connection is Interrupted (the Endpoint_OnConnectionEvent recieves the "ConnectionEvent.ConnectionInturrepted"), you cannot close the connection via "endpoint.Close()"
When attempting to close it sends the event "ConnectionEvent.ConnectionFailed" and doesnt actually close the connection as far as im aware.
Is there a way to dispose of this connection in a more permanant fashion?
I've set up amqp v1.0 broker by enable rabbitMQ plugin rabbitmq_amqp1_0.
At the broker side, error occurred when publish message with APEX CFX Demo Examples(or app) project.
The following is error message
handshake_error,running,<0.26804.0>,
{{symbol,"amqp:internal-error"},
"Session error: pnpn",
[function_clause,
[{rabbit_amqp1_0_framing,fill_from_binary,
[{'v1_0.amqp_value',undefined},
However, There is noting error when I used Qpid as producer.
Is anything missing at broker setting or APEX CFX Demo Examples project(or app) needs to be modified?
Hello,
I am missing an identifier for ReflowProcessData. How to know which board was processed with this process data without identifier?
Thanks in advance.
Can the CFX SDK be imported into a .NET Core project?
The messages which are triggered to send which did not reach the broker are stored in a local file on the client. This file is stored in the TEMP directory. See code below.
public DurableQueue(string name)
: base()
{
dataName = System.IO.Path.GetTempPath();
dataName += (@"" + name + ".cache");
Initialize();
}
This might not be survive a reboot, because some customer computer polcies will clean the TEMP directory.
Not sure if this is the place to ask this , but i'm having some trouble connecting the demo app to the connected facory. I've entered a unique Handle ( do i need to request one first? ) and the app seems to connect, yet i dont see any changes in the connected factory.
Hi,
In order for my software to retrieve and use PCB data such as CAD files after getting a UnitsInspected or UnitsTested, it needs a PartNumber.
One can find the board part number in the WorkOrder class. And a CFX.InformationSystem.WorkOrderManagement.WorkOrdersCreated message should be published to make available the data about a new board product being produced.
Then a CFX.Production.UnitsInitialized message should be published to make available the list of all the "PartNumber" units in production. The WorkOrderIdentifier referring to the previously published corresponding WorkOrder.
Ex:
"WorkOrderIdentifier": { "WorkOrderId": "WO45648798", "Batch": "BATCH45648798-1" }, "Units": [ { "UnitIdentifier": "UNIT5566687", "PositionNumber": 1, "PositionName": "CIRCUIT1", "X": 50.45, "Y": 80.66, "Rotation": 0.0, "FlipX": false, "FlipY": false }, { "UnitIdentifier": "UNIT5566688", "PositionNumber": 2, "PositionName": "CIRCUIT2", "X": 50.45, "Y": 80.66, "Rotation": 90.0, "FlipX": false, "FlipY": false } ]
So, here is my question: Is it the right/only way to connect the UnitIdentifier (SN) to the PCB PartNumber, publishing WorkOrdersCreated, UnitsInitialized and then for example UnitsInspected ?
Thank you
The goal of this issue to help ensure that the CFX standard is able to support future message serialization formats and compression types easily without a danger to any existing client that may not support them. In order to enable this, there needs to be a clear way for a client to know the chosen serialization and compression format before trying to decode a message.
Currently the CFX SDK sends CFX messages serialized as JSON objects with optional deflate compression. The CFX standard calls out that future versions may support different (potentially nonjson) serialization formats and likely more compression algorithms on top of those underlying serialization formats.
Without a clear way to obtain the chosen compression/serialization formats from a received cfx message itself, it could be very difficult to safely allow multiple formats to coexist on the same broker since clients would have to guess what combination of serialization/compression was used for a given message.
AMQP 1.0 has standard properties to include these two values (content-type and encoding) in a globally understood way. Setting both properties now to valid MIME types will help ensure that future additions of other choices for either serialization format or compression will not negatively impact existing clients since they will be able to inspect the message properties and know how to decode it.
The AMQP 1.0 protocol has a standardized way of communicating both serialization format using the content-type
property and optional compression using the content-encoding
property.
AMQP 1.0 defines that both content-type
and content-encoding
properties, when set should be valid MIME content-types.
Currently, the CFX SDK does not set content-type
explicitly and sets content-encoding
to a non-null value only when compressing, in which case it uses a nonstandard value CFX-COMPRESSED
.
See: https://github.com/IPCConnectedFactoryExchange/CFX/blob/master/CFX/Transport/AmqpUtilities.cs#L66
The AMQP 1.0 standard specifies that content-encoding
must be an IANA registered MIME type (see amqp 1.0 standard page 78).
The following is a list of potential ways to address the above described issue for consideration and disuccsion.
content-type
header on all messages with MIME type application/json
CFX-COMPRESSED
to, for example, application/x-gzip
.content-type
and content-encoding
and validate their contents before decoding. This will allow clients to operate in a mixed encoding environment with clear error messages when receiving a message they are not able to decode (due to unknown serialization format or compression type)content-type
header as a synonym for application/json
to allow full backwards compatibility with legacy senders that do not set content-type
correctly.CFX-COMPRESSED
as a synonym for no-compression to allow full backwards compatibility with legacy senders that send a nonstandard content-encoding
value. See https://github.com/IPCConnectedFactoryExchange/CFX/blob/master/CFX/Transport/AmqpUtilities.cs#L123string myHandle = "MyCompany.MyMachineModel.MyMachineSerialNumber";
string myBroker = "amqp://cfx.aiscorp.com:5672";
string myExchange = "/exchange/AegisCloud";
theEndpoint = new AmqpCFXEndpoint();
theEndpoint.Open(myHandle);
theEndpoint.AddPublishChannel(new Uri(myBroker), myExchange);
Hi,
Today, there are only 3 members in CFX.Structures InspectionMethod Enumeration:
Human, AOI, SPI
is AXI (Automatic X-ray Inspection) considered as AOI in CFX ?
And what about these methods of inspection?
All these tests methods/machines should be able to send CFX.Production.TestAndInspection messages. Are they missing or is there another explanation ?
In the list of machines already registered in the online, CFX Demo, I can see AXI, ICT and SMT tests machines with no InspectionMethod to use.
Thank you
Daniel Siran
ASTER Technologies
I am attempting to implement the example code in LabVIEW (so apologies for the lack of .NET fluency), and when I look at sending a StationStateChanged message as shown on this page, I see NewState = ResourceState.On, OldState = ResourceState.Off.
In looking at the source for ResourceState I do not see On and Off defined.
Are these just assumed Boolean constants (On = 1 and Off = 0)?
Would it be poor practice to send a message about a Station State and not use one of the defined ResourceState enumerations?
Thanks!
Hi,
The CFX.Production.Assembly.MaterialsInstalled and CFX.Production.Assembly.MaterialsUninstalled messages are defining the installed and uninstalled materials on a production unit.
But what about the "not installed" materials? (like for instance components rejected by vision test). It should be interisting to have a CFX.Production.Assembly.MaterialsNotInstalled message as it's different from the CFX.Production.Assembly.MaterialsUninstalled message, and it should fill the hole.
We are ready to code this message but we want to be sure that we understand those existing messages as they were designed.
Alexis FOUQUET.
Hi,
Currently, CFX WorkCompleted message has no response message described in CFX standard.
In our use case, when AOI sends "WorkCompleted" to MES interface, AOI operator should see feedback from MES. MES Response will contain information, how message processing ended in MES interface (Ok/Error)
What could be best CFX message to use for this purpose?
Currently, the AMQP 1.0 serialization of CFX messages appears to consist of:
json
sourcejson
envelope that contains the message topic, source, target, id and a few other fields. sourceThis means that there is no information about the contents of the message available in a format that can be used to route or filter the messages based on, for example, topic.
Each machine can be configured to send all messages generated to a single fixed target
address but, if that target is a message broker, there is no exposed information to allow the broker to route individual messages to different queues. An example use case would be:
There are two systems interested in different CFX messages. One system just wants placement data to show a realtime line dashboard. It is a small computer, perhaps a low-cost IoT linux device that expects to receive a low volume of CFX messages.
There is a second system that performs level 4 traceability and receives detailed reports of all components installed on each production unit.
As I understand it, there is no way currently to set up a single amqp 1.0 broker that would be able to receive all messages from a machine and route the performance topic only to system 1 and all messages to system 2.
As the size of CFX installations grow, the implicit use of fanout-only exchanges in this way could cause rapid resource need expansion or complex manually configuration of machines in order to have multiple targets with specific messages sent to each target. This latter setup partially negates the benefit of using a pub/sub compatible protocol like amqp 1.0 which inherently has a way to achieve this goal without needing multiple links to each machine.
The current issue blocking such a centralized cfx broker deployment is that the cfx message to amqp 1.0 mapping does not appear to include metadata like topic and cfx version in a way that the amqp broker can access to make routing decisiosn.
This a potential solution to the above issue proposed here for discussion and brainstorming with the CFX team.
Include key information from the cfx envelope in the amqp 1.0
"application properties" section of the message. See amqp 1.0 Page 80.
This header section is reserved by amqp 1.0 for applications like cfx to include a key/value map of information that is designed to be used to route messages without parsing the message contents.
If, for example, the cfx message topic, source, target and cfx version were duplicated as application properties, then you would be able to route a subset of messages based on topic to a subset of consumers.
RabbitMQ has a mapping of amqp 1.0 application headers to amqp 0.9.1 headers
which allows them to be used with a rabbitmq header exchange to perform complex filtering and routing. By adding the cfx topic to application headers then users would be able to set up complex routing scenarios needed by large deployments with no backwards-compatibility implications.
See here
I believe that cloud amqp 1.0 compliant messaging systems also look at application headers to allow for programmatic routing. For example, Azure Service Bus maps application headers
to User Properties (see here).
User Properties can be used to filter message subscriptions. (see here).
Adding key information to the application properties section of the AMQP messages (in addition to placing it in the json
envelope wrapper) will facilitate large CFX deployments since it permits brokers to route subsets of messages.
This benefit comes at no cost to point-to-point installations (or small fanout style exchanges) that do not need to worry about resource optimization.
Adding this information sooner rather than later can hopefully ensure that the majority of CFX implementations adopt it so that their messages can be routed in a manner other than point-to-point or fanout.
I would like to be able to host the amqp service myself, with something like RabbitMQ. Has anyone been able to use this with anything other than the amqp://cfx.aiscorp.com:5672 broker? I've tried setting settings up an exchange/queue that has similar naming, but none of the messages seem to come through. I'd appreciate any insight anyone could give me into this. Thanks!
Hi,
i have a question regarding the process interlock via barcode scanner with CFX. As soon as the barcode is read by the scanner, which CFX message should be used for sending this to the broker? Furthermore is there a response with the program to load or is the program load done separately by the broker with a load program call? If yes what is the name of the CFX request from the host to the equipment?
Thanks in advance for your answers.
Regards
Hi,
I think we need PCB specification information in GetEndpointInformationResponse message.
And we also need software information in it.
So I recommend that we add the following in EndpointInformation.
"EndpointInformation" : {
... ...
"UnitSpecification" : {
"MaxUnitSize" : 100.0,
"MinUnitSize" : 30.0,
"MaxComponentHeight" : 10.0,
"MaxUnitWeight" : 100.0
},
"Software" : {
"SystemFirmware" : "PLC XXX AA 1.0",
"OperationSystem" : "Windows 7 Home Edition",
"SoftwareName" : "Printer Professional",
"SoftwareRevision" : "1.25"
}
}
The following works on Forms (CFX.CFXSDK)
AmqpCFXEndpoint.RequestTimeout = TimeSpan.FromSeconds(30);
AmqpCFXEndpoint endpoint = new AmqpCFXEndpoint();
endpoint.Open("MachineName");
String Username = "sample";
String Password = "sample";
String Hostname = "localhost";
String Port = "5672";
Uri BrokerUri = new Uri($"amqp://{Username}:{Password}@{Hostname}:{Port}");
String BrokerAddress = "/exchange/sample_exchange/sample_routingKey";
Exception exception = null;
if (!endpoint.TestChannel(BrokerUri, out exception))
{
Console.WriteLine("ERROR: Unable to connect to RabbitMQ" + Environment.NewLine);
Console.WriteLine($"URI = {BrokerUri}" + Environment.NewLine);
Console.WriteLine($"ERROR MESSAGE = {exception.Message}" + Environment.NewLine);
return;
}
else
{
Console.WriteLine("Connection To RabbitMQ broker Successful" + Environment.NewLine);
}
if (!endpoint.TestPublishChannel(BrokerUri, BrokerAddress, out exception))
{
Console.WriteLine("ERROR: Unable to establish connection to RabbitMQ Broker exchange" + Environment.NewLine);
Console.WriteLine($"URI = {BrokerUri}" + Environment.NewLine);
Console.WriteLine($"ADDRESS = {BrokerAddress}" + Environment.NewLine);
Console.WriteLine($"ERROR MESSAGE = {exception.Message}" + Environment.NewLine);
return;
}
else
{
Console.WriteLine("Connection to RabbitMQ broker exchange is successful." + Environment.NewLine);
}
endpoint.AddPublishChannel(BrokerUri, BrokerAddress);
CFXEnvelope env = new CFXEnvelope()
{
MessageBody = new EndpointConnected()
{
CFXHandle = "SampleCFXHandle",
RequestNetworkUri = "request URI",
RequestTargetAddress = "Sample MEssage to publish"
}
};
endpoint.Publish(env);
Console.WriteLine("Message had been published.");
But when I tried the same for Console version (CFX.CFXSDK.NetCore). The message is not published when I tried to run the application.
May I know if it uses a different approach to write the codes to publish the message if I am using CFX Core instead of using the CFX.CFXSDK?
Thank you.
Regards
Snow Bunny.
Many cloud based amqp messaging layers such as Azure ServiceBus have a hard upper limit on maximum message site. For example Azure standard permits messages up to 256kb for standard tier and 1MB for a more expensive tier.
Given that CFX compliant machines natively send data via AMQP 1.0, it makes sense that a key future if not present deployment scenario would be to directly have the machines send their data to an AMQP 1.0 broker hosted, for example, on Azure. There are other cloud based services as well.
However, there's a potential blocking issue in that certain messages inside the CFX standard, specifically the test and inspection messages generated by SPI and AOI machines have a potentially unbounded size, even with compression because they list a CFX structure for every defect found or every measurement performed and there can be a large number of these entries, which in practice push the message size over the 256kb limit (upwards of 20-30MB without compression and even 2-3MB with gzip compression).
So, the question is, would it be feasible to define a "maximum message size" for CFX messages that we could always ensure messages stay within so they are feasible to send to a broker with fixed max message size. Given that the amount of data that needs to be sent is unchanged, this would imply a fragmentation scheme of some sort to split a single message across multiple AMQP messages, each under the maximum size.
This issue lays out options for achieving this with some discussion of pros/cons of each one.
I see two major axes to decide on fragmentation and a third potential out-of-band option:
Fragment before or after compression, i.e. fragment the json and then compress each message separately, or compress the message and then just split it across multiple messages.
Transport level or application level fragmentation.
Out of band transmission with inclusion of a unique pointer.
In this option, no message is fragmented but for messages that could have large "extra data" like measurements or defect counts, there's a defined way to include a pointer to that data and a way to fetch it. For example, it could be that the message contains a unique URL in place of a large substructure (like the list of measurements in an aoi inspection report) where more data could be downloaded from another server out-of-band with the amqp messaging.
This section covers some of the implications of the various choices we might choose from above. In particular, I see the following major question:
Is it assumed that a given fragmented message will always be received by a single worker process in order? If this can be guaranteed, then fragmenting after compression is fine and transport level fragmentation is a good choice because we're basically just splitting a single message up and its going to be put back together on the other side of the link by a single worker with no ambiguity.
However if there is load balancing of messages where multiple messages for a single machine might be handled by multiple workers then having messages that can't be interpreted on their own is problematic because different worker processes may receive different fragments.
Since this is a cloud based system you would expect load balancing for scaleability but there could be a sticky association of messages from a single machine to a single worker that could allow this to work.
This would definitely be the simplest implementation:
max_size
bytes and send as its own messageYou could mark each message in the amqp header with a Fragment N of M
header to allow reconstruction.
This option is predicated on a belief that there is value in being able to consider a "primary message" containing the "gist" of the event with subsequent addendum messages filling in details that not everyone may care about.
This could make sense, for example, for TestAndInspection AOI inspection reports:
In this sense there is no fragmentation per se but rather just a clear understanding of which messages are fixed size vs flexible size and for those that are flexible size, the definition of addendum messages (which could be the same message but with a flag or field set to indicate they are addendums to a previous message) containing certain details.
This is another alternative to the problem where there's an agreed upon set of ways to transfer "large amounts of data" that don't make sense to include in an amqp message. In that case what's included in the message is a unique pointer to fetch the large attachment from a different server that it was sent to out-of-band.
An example of how this could play out would be that:
$external_url=URL
key in place of the array data to indicate that it should be fetched from a 3rd party server.Basically this would be the definition of a way to send files in addition to messages and a way to replace part of a message with a reference to an external file.
Given the 3 options, it's not clear to me which one stands out as a clear winner. Each one has pros and cons and makes sense given a particular view on how you expect the standard to be implemented.
Currently, I lean toward either the application level fragmenting with addendum messages or the out of band reference option but look forward to discussing more to see what could make the most sense.
Hi,
At this point, only one message is concerned by Broadcast Request (WhoIsThereRequest).
Is the current CFX code able to handle it?
The request function is defined like this :
public CFXEnvelope ExecuteRequest(string targetUri, CFXEnvelope request);
So it allows to only get one answer of one answering end point, not several.
Thanks for your feedback,
Alexis FOUQUET
R&D Software Engineer, EUROPLACER.
public void Open(string cfxHandle, Uri requestUri, X509Certificate2 certificate = null)
{
IsOpen = false;
if (string.IsNullOrEmpty(cfxHandle)) throw new ArgumentException("You must supply a CFX Handle");
this.CFXHandle = cfxHandle;
RequestUri = requestUri;
**inboundHost = new ContainerHost(RequestUri);**
In the setup guide it states it is possible to bind queues to and Exchange within the CFX SDK.
Source: https://cfx.ipc.org/files/IPC-CFX-AMQP-Guide-v1_0.pdf
Page: 6
There is no indication that this is possible in the github source, im not sure if im missing something but it doesnt seem like it is possible to do this in the current SDK.
If this is not possible how are new machines or analizers expected to be added to a network or line? is it just manual?
Hi.
at the moment i am implementing PCBSelectiveSoldered in our project.
The problem is that the model is too simple for our machines.
First of all let me explain how our machines look like.
They can have multiple soldering stages, preheating stages and fluxing stages.
A soldering stage may have multiple axis systems. On an axis system there can be one or more soldering heads.
A flux stage may also have multiple axis systems. Each of them can have multiple bottles with different pressure and multiple flux heads with different consumption.
The PCBSelectiveSoldered class has the property SolderedPCBs which is a list of SelectiveSolderedPCB. The SelectiveSolderedPCB class has the property ZoneData which is a list of ZoneData. The ZoneData look like this.
So if I get everything right, the idea is that for every stage the pcb went through, you create a ZoneData object and fill it with the data of the stage.
Some examples to explain the problem in my mind:
So what is the best solution for this? Should I split the phyiscal stages into seperate stages in the model? Should I just send the temperature of one bath, and ignore the values of the second bath?
For me, the best solution would be to adapt the models to allow more complex data. For example we could either make values like the Bath_Temp a list, or instead we could add a deeper level for data with some kind of SubStageSequence property. I would offer to implement it and create a PR. But first, i wanted to discuss the architecture.
The PCBSelectiveSoldered class has the property HeaderData which is of type SelectiveSolderData. The SelectiveSolderData looks like this.
So when I understood that correctly, the idea is that for a soldered pcb, there is one single value of nitrogen flow (Nitrogen_Flow).
Again, in our machines, there are multiple of these values.
This is not a real problem but something strange. Why do the property names have an underscore in their name? Is there a reason for that?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.